Как с помощью grep / print значение ключа в json, которое хранится в переменной?

Если вы имеете в виду, что замена не должна выполняться, если имеется более 8 соседних (TAB) s, вы можете сделать:

sed '
   s/_/_u/g; # escape _
   s/|/_p/g; # escape |
   s/(TAB)/|/g; # use a single character in place of (TAB)
   s/.*/<&>/; # add leading and trailing non-| character
   s/\([^|]\)|\{2,8\}\([^|]\)/\1|\2/; # replace up to 8 | provided
                                      # they are not preceded nor followed
                                      # by |
   s/.\(.*\)./\1/; # undo wrapping
   s/|/(TAB)/g;    # undo replacement
   s/_p/|/g;s/_u/_/g; # undo escaping'

Если ваш sed (например, ssed ) поддерживает регулярные выражения, подобные Perl, вы можете использовать операторы просмотра:

ssed -R 's/(?<!\(TAB\))(\(TAB\)){2,8}(?!\(TAB\))/(TAB)/g'

Или использовать perl напрямую:

perl -lpe 's/(?<!\(TAB\))(\(TAB\)){2,8}(?!\(TAB\))/(TAB)/g'

AT&T (ast-open) sed ], с параметром -A / -X поддерживается разновидность расширенных регулярных выражений, которые они называют дополненными , которые имеют оператор отрицания ( x! ) и оператор конъюнкции ( x & y ). Здесь (. {5} & (\ (TAB \))!) соответствует последовательности из 5 символов, которая является , а не (TAB) . Итак, с помощью этого sed вы можете сделать что-то вроде:

sed -A '
  :1
    s/(^.{0,4}|.{5}&(\(TAB\))!)(\(TAB\)){2,8}(.{0,4}$|.{5}&(\(TAB\))!)/\1(TAB)\4/
  t1'
3
18.07.2017, 18:06
4 ответа

Я поклонник использования Perl для подобных вещей

echo $a | grep -oP '(?<=DATE**:).*?(?=,)'

и

echo $a | grep -oP '(?<=START_TIME**:).*?(?=,)'

0
27.01.2020, 21:15

Используйте jq:

$ echo $a | jq '.[][0]["**DATA_DATE**"]'
"2017-03-09 00:00:00"

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

Перл:

$ perl -e "use JSON::Parse 'parse_json'; my \$a = parse_json ('$(echo $a)'); print \$a->{'content'}[0]{'**DATA_DATE**'}"
2017-03-09 00:00:00

Питон:

$ python -c "import json; a=json.loads('$(echo $a)'); print(a['content'][0]['**DATA_DATE**'])"
2017-03-09 00:00:00

Рубин:

$ ruby -e "require 'json'; puts JSON.parse('$a')['content'][0]['**DATA_DATE**'];"
2017-03-09 00:00:00

Конечно, вы можете (ab )использовать стандартные инструменты *nix (GNU )для получения значений из этого конкретного примера JSON, но это действительно неудобно. Вы можете занять первую строку. Как только структура JSON изменится, ваш код будет вести себя непредсказуемо.

2
27.01.2020, 21:15

Как говорили другие, гораздо лучше использовать язык, (такой как perl, python или ruby ​​), которые имеют библиотеки для синтаксического анализа json, или специальный -целевой инструмент, который делает это как jq... но если вы действительно хотите или должны обрабатывать данные json с помощью обычных инструментов, таких как awkили sed, вам сначала нужно преобразовать их в формат, ориентированный на строку -.

Почему? Потому что вы не можете надежно анализировать json только с помощью регулярных выражений, и даже если вы думаете, что преуспели, то, что у вас есть, будет невероятно хрупким и склонным к поломке даже при незначительных изменениях ожидаемого ввода.

jsonpipe(, написанный на python ), является одним из таких инструментов, который может выполнять преобразование в формат, ориентированный на строку -. например. после исправления сломанного json в вашем примере он выдает следующий вывод:

$ jsonpipe < /tmp/nick.json 
/   {}
/content    []
/content/0  {}
/content/0/JOB_STATUS_ID    283739
/content/0/PROGRAM_ID   57
/content/0/STATUS   "Completed"
/content/0/**DATA_DATE**    "2017-03-09 00:00:00"
/content/0/**START_TIME**   "2017-03-10 00:46:13"
/content/0/END_TIME "2017-03-10 00:56:40"
/content/0/TOTAL_ROWS   null
/content/0/UPDATED_ROWS null
/content/0/DELETED_ROWS null
/content/0/INSERTED_ROWS    null
/content/0/REF1 "NULL"
/content/0/REF2 "NULL"
/content/0/AUD_CREATE_DT    "2017-03-10 00:46:13"
/content/0/AUD_CREATE_USER  "JOB_CONTROL"
/content/0/AUD_MODIFY_DT    "2017-03-10 00:56:40"
/content/0/AUD_MODIFY_USER  "JOB_CONTROL"
/content/1  {}
/content/1/JOB_STATUS_ID    109711
/content/1/PROGRAM_ID   57
/content/1/STATUS   "Completed"
/content/1/DATA_DATE    "2017-01-11 00:00:00"
/content/1/START_TIME   "2017-01-12 16:55:14"
/content/1/END_TIME "2017-01-12 18:54:51"
/content/1/TOTAL_ROWS   null
/content/1/UPDATED_ROWS null
/content/1/DELETED_ROWS null
/content/1/INSERTED_ROWS    null
/content/1/REF1 "NULL"
/content/1/REF2 "NULL"
/content/1/AUD_CREATE_DT    "2017-01-12 16:55:14"
/content/1/AUD_CREATE_USER  "JOB_CONTROL"
/content/1/AUD_MODIFY_DT    "2017-01-12"

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

$ jsonpipe < /tmp/nick.json  | \
  sed -ne 's:^/content/0/\*\*DATA_DATE\*\*[[:space:]]\+::p'
"2017-03-09 00:00:00"

$ jsonpipe < /tmp/nick.json  | \
  awk -F'"' '/^\/content\/0\// && /DATA_DATE/ {print $2}'
2017-03-09 00:00:00

или даже что-то столь грубое, как это:

$ jsonpipe < /tmp/nick.json  | grep '/0/.*DATA_DATE'
/content/0/**DATA_DATE**    "2017-03-09 00:00:00"

В debian и производных системах он упакован как python-jsonpipeи, вероятно, имеет похожее имя пакета в других дистрибутивах. Или его можно найти по адресуhttp://pypi.python.org/pypi/jsonpipe

ПРИМЕЧАНИЕ. :он поставляется с соответствующим jsonunpipeинструментом, который вы можете использовать для преобразования этого формата, ориентированного на строку -, обратно в json -, например. после изменения его с помощью sedили awkили чего-то еще.

0
27.01.2020, 21:15

Для JSON вы используете инструмент, который понимает JSON, например. jq , а не awk/sed:

$ echo "$a" | jq '.content[0].DATA_DATE'
"2017-03-09 00:00:00"

Аналогично для START_TIME. Для большинства дистрибутивов jq доступен в виде пакета.

1
27.01.2020, 21:15

Теги

Похожие вопросы