2016-07-14 5 views
8

Я пытаюсь разобрать объект JSON внутри скрипта оболочки в массив.Parse JSON для массива в скрипте оболочки

например: [Аманда, 25, http://mywebsite.com]

JSON выглядит следующим образом:

{ 
    "name"  : "Amanda", 
    "age"  : "25", 
    "websiteurl" : "http://mywebsite.com" 
} 

Я не хочу использовать какие-либо библиотеки, было бы лучше, если бы я мог бы использовать регулярное выражение или Grep , Я сделал:

myfile.json | grep name 

Это дает мне «имя»: «Аманда». Я мог бы сделать это в цикле для каждой строки в файле и добавить его в массив, но мне нужна только правая сторона, а не вся строка.

+3

Используйте 'jq' для этого. – sjsam

+0

Посмотрите на [\ [this \]] (http://unix.stackexchange.com/questions/177843/parse-one-field-from-an-json-array-into-bash-array) вопрос и шоу мы с вашей стороны решили немного решить эту проблему. – sjsam

+1

Этот 'cat myfile.json | имя grep | cut -d ':' -f2' может помочь. –

ответ

14

Если вы действительно не можете использовать правильный JSON парсер, такие как jq[1] , попробуйте awk -На решение:

Bash 4.x:

readarray -t values < <(awk -F\" 'NF>=3 {print $4}' myfile.json) 

Bash 3 .x:

IFS=$'\n' read -d '' -ra values < <(awk -F\" 'NF>=3 {print $4}' myfile.json) 

В этом магазине все имущество значения в массиве Баша ${values[@]}, которое вы можете проверить с помощью
declare -p values.

Эти решения имеют ограничения:

  • каждое свойство должно быть по своей линии,
  • все значения должны быть в двойных кавычках,
  • внедренные сбежавшие двойные кавычки не поддерживаются.

Все эти ограничения подкрепляют рекомендацию использовать надлежащий парсер JSON.


Примечание: Следующие альтернативные решения используют Bash 4.x + readarray -t values команду, но они также работают с альтернативой Bash 3.x, IFS=$'\n' read -d '' -ra values.

grep + cut сочетание: один grep команда не будет делать (если вы не используете GNUgrep - смотри ниже), но добавление cut помогает:

readarray -t values < <(grep '"' myfile.json | cut -d '"' -f4) 

GNUgrep: Использование -P для поддержки PCRE, которые su pport \K бросить весь согласованные до сих пор (более гибкой альтернативу просмотрового за утверждение), а также прогнозные утверждения ((?=...)):

readarray -t values < <(grep -Po ':\s*"\K.+(?="\s*,?\s*$)' myfile.json) 

Наконец, вот чистого Bash (3 .x +) решение:

что делает это жизнеспособной альтернативой с точки зрения производительности является то, что никакие внешние утилиты не вызываются в каждой итерации цикла; однако для больших входных файлов решение на основе внешних утилит будет намного быстрее.

#!/usr/bin/env bash 

declare -a values # declare the array                                         

# Read each line and use regex parsing (with Bash's `=~` operator) 
# to extract the value. 
while read -r line; do 
    # Extract the value from between the double quotes 
    # and add it to the array. 
    [[ $line =~ :[[:blank:]]+\"(.*)\" ]] && values+=("${BASH_REMATCH[1]}") 
done < myfile.json                                   

declare -p values # print the array 

[1] Вот что надежное jq основанное решение будет выглядеть (Bash 4.x):
readarray -t values < <(jq -r '.[]' myfile.json)

0

Вы можете использовать SED один лайнер для достижения этой цели:

array=($(sed -n "/{/,/}/{s/[^:]*:[[:blank:]]*//p;}" json)) 

Результат:

$ echo ${array[@]} 
"Amanda" "25" "http://mywebsite.com" 

Если вам не нужны/хотят кавычки, то следующий СЕПГ покончит с ними:

array=($(sed -n '/{/,/}/{s/[^:]*:[^"]*"\([^"]*\).*/\1/p;}' json)) 

Результат:

$ echo ${array[@]} 
Amanda 25 http://mywebsite.com 

Он также будет работать если у вас есть несколько записей, например

$ cat json 
{ 
    "name"  : "Amanda" 
    "age"  : "25" 
    "websiteurl" : "http://mywebsite.com" 
} 

{ 
    "name"  : "samantha" 
    "age"  : "31" 
    "websiteurl" : "http://anotherwebsite.org" 
} 

$ echo ${array[@]} 
Amanda 25 http://mywebsite.com samantha 31 http://anotherwebsite.org 

ОБНОВЛЕНИЕ:

Как указано в комментариях mklement0, может возникнуть проблема, если файл содержит встроенные пробелы, например "name" : "Amanda lastname". В этом случае Amanda и lastname оба будут считываться в отдельные поля массива каждый. Чтобы избежать этого, вы можете использовать readarray, например,

readarray -t array < <(sed -n '/{/,/}/{s/[^:]*:[^"]*"\([^"]*\).*/\1/p;}' json2) 

Это будет также заботиться о любых глобирование вопросов, также упомянутых в комментариях.

+3

Пожалуйста, не разбирайте вывод команды в массив с помощью 'array = ($ (...))' (даже если это работает с образцом ввода): он не работает так, как предполагалось, со встроенными пробелами и может привести к в случайном глотании. – mklement0

+0

@ mklement0 Можете ли вы привести пример того, как должно выглядеть содержимое образцового файла для случайного переполнения? – nautical

+0

Чтобы узнать, что делает ваш подход к встроенным пробелам, рассмотрите массив, который получается из 'array = ($ (echo 'a b'))'; чтобы увидеть эффекты случайного глобирования, попробуйте 'array = ($ (echo 'a * born))). – mklement0

3

JQ достаточно хорошо, чтобы решить эту проблему

paste -s <(jq '.files[].name' YourJsonString) <(jq '.files[].age' YourJsonString) <(jq '.files[].websiteurl' YourJsonString) 

Так что вы получите таблицу, и вы можете вычленить какие-либо строки или AWK печать любые столбцы, которые вы хотите

Смежные вопросы