У меня есть куча журналов из двух столбцов, разделенных вкладками. Второй столбец является действительным JSON:
2019-02-28T19:43:48.585Z {"id": 1234, "catId": 42, "img": "other.jpg"}
2019-02-28T19:44:48.585Z {"id": 4321, "catId": 999, "img": "my.jpg"}
2019-02-28T19:44:48.585Z {"id": 1234, "catId": 42, "img": "new.jpg"}
2019-02-28T19:46:48.585Z {"id": 1234, "catId": 765, "img": "cat.jpg"}
Моя цель сохранить столбец метки времени и распечатать свойство catId:
2019-02-28T19:43:48.585Z 42
2019-02-28T19:44:48.585Z 999
2019-02-28T19:44:48.585Z 42
2019-02-28T19:46:48.585Z 765
До сих пор я пытался подключить jq к awk, но я борюсь с командой system.
awk -F '\t' '{printf "\n %s \t %s \n", $1, system("jq .catId <<< " $2)}' file
Любая помощь в правильном направлении будет высоко оценена.
tr '\t' ' ' | cut -d' ' -f1,5 - сработает, если повезет, так что в полях внутри json нет пробелов.
system() Awk почти никогда не следует использовать — его использование сопряжено с серьезными рисками для безопасности. <<<"$2" в оболочке безопасен, потому что он никогда не будет интерпретировать содержимое в $2 как код, но если бы у вас был "img": "$(rm -rf ~).jpg" во входном документе, у вас был бы плохой день очень сильно с заменой system() awk на то же значение, потому что awk не Нет никакого способа сообщить оболочке, которую она вызывает, с помощью system(), какие символы могут быть синтаксическими, а какие — литеральными данными.
... можно было бы считать, что размещение буквенных кавычек в контенте, добавленном awk, позволит избежать этого риска, но это не так, потому что буквальное содержимое также может содержать буквальные кавычки: рассмотрим файл с именем $(rm -rf ~)'$(rm -rf ~)'.jpg; левый раскрывается в двойных кавычках, правый раскрывается в одинарных кавычках.

Если файлы разделены табуляцией, вы можете прочитать файл в необработанном виде, разделить на вкладки, проанализировать и извлечь json, а затем воссоединиться на вкладках.
$ jq -Rr 'split("\t") | .[1] |= fromjson.catId | join("\t")' input.log
Не могли бы вы объяснить, что делает |=?
@test: Assignments = просто берет значение справа и обновляет поле слева. Контекст для этого значения не изменился, что означает, что «ввод» для значения — это тот же ввод в LHS. Использование |= изменяет контекст, так что «вводом» для значения является значение LHS.
@Jeff, можно ли добавить еще один элемент массива? псевдокод: .[1] |= fromjson.catId .[2] = fromjson.another'
@test: Вы должны уметь: ... | . += [$yourItem] | .... Я лично предпочитаю: ... | [.[], $yourItem] | ...
@Джефф. не может заставить это работать. Работает со статической строкой, такой как ... | [.[], "foo"] | ..., но не с динамической ... | [.[], fromjson.id] | ...
@test: вам нужно знать текущий контекст. В вашем примере массив элементов является текущим «входом», поэтому использование fromjson в этом массиве будет ошибкой. это работает только в ответе выше, потому что мы изменили контекст, чтобы он был вторым элементом в массиве (.[1] |= ...), если вы хотите добавить несколько значений из этого одного объекта, вы захотите сделать это в рамках этого обновления-назначения. например, ... | .[1:] |= (.[0] | fromjson | [.catId, .img]) | ... (обратите внимание на изменение в LHS)
Просто добавьте, почему ваш код не работает, поскольку предыдущие ответы лучше. В вашем случае $2 интерпретировался jq как несколько аргументов, поскольку $2 содержит пробелы.
Итак, в приведенном ниже коде $2 помещается в шестнадцатеричные значения в одинарных кавычках \x27, а затем в двойных кавычках.
Также немного форматирования, чтобы сохранить вывод в одной строке.
awk -F '\t' '{printf "%s\t", $1;system("jq .catId <<< \x27"$2"\x27")}' file
Вывод:
2019-02-28T19:43:48.585Z 42
2019-02-28T19:44:48.585Z 999
2019-02-28T19:44:48.585Z 42
2019-02-28T19:46:48.585Z 765
в баш:
while IFS=$'\t' read -r timestamp json; do
printf '%s\t%s\n' "$timestamp" "$(jq -r .catId <<<"$json")"
done < file
это будет намного медленнее, чем jq oneliner.
awk '{sub(/,/,"",$5);print $1"\t"$5}' file
2019-02-28T19:43:48.585Z 42
2019-02-28T19:44:48.585Z 999
2019-02-28T19:44:48.585Z 42
2019-02-28T19:46:48.585Z 765
Использование Perl
perl -lanE ' $x=$_=~s/(^.*catId":\s*)(\d+).*$/$2/gr; print "$F[0]\t$x" '
с заданными входами
$ cat test.log
2019-02-28T19:43:48.585Z {"id": 1234, "catId": 42, "img": "other.jpg"}
2019-02-28T19:44:48.585Z {"id": 4321, "catId": 999, "img": "my.jpg"}
2019-02-28T19:44:48.585Z {"id": 1234, "catId": 42, "img": "new.jpg"}
2019-02-28T19:46:48.585Z {"id": 1234, "catId": 765, "img": "cat.jpg"}
$ perl -lanE ' $x=$_=~s/(^.*catId":\s*)(\d+).*$/$2/gr; print "$F[0]\t$x" ' test.log
2019-02-28T19:43:48.585Z 42
2019-02-28T19:44:48.585Z 999
2019-02-28T19:44:48.585Z 42
2019-02-28T19:46:48.585Z 765
$
awk -F ' *|\t*|,' '{print $1,$6}' file?