Получить значение JSON из столбца

У меня есть куча журналов из двух столбцов, разделенных вкладками. Второй столбец является действительным 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

Любая помощь в правильном направлении будет высоко оценена.

awk -F ' *|\t*|,' '{print $1,$6}' file?
Cyrus 28.02.2019 21:23
tr '\t' ' ' | cut -d' ' -f1,5 - сработает, если повезет, так что в полях внутри json нет пробелов.
KamilCuk 28.02.2019 21:34

system() Awk почти никогда не следует использовать — его использование сопряжено с серьезными рисками для безопасности. <<<"$2" в оболочке безопасен, потому что он никогда не будет интерпретировать содержимое в $2 как код, но если бы у вас был "img": "$(rm -rf ~).jpg" во входном документе, у вас был бы плохой день очень сильно с заменой system() awk на то же значение, потому что awk не Нет никакого способа сообщить оболочке, которую она вызывает, с помощью system(), какие символы могут быть синтаксическими, а какие — литеральными данными.

Charles Duffy 28.02.2019 21:59

... можно было бы считать, что размещение буквенных кавычек в контенте, добавленном awk, позволит избежать этого риска, но это не так, потому что буквальное содержимое также может содержать буквальные кавычки: рассмотрим файл с именем $(rm -rf ~)'$(rm -rf ~)'.jpg; левый раскрывается в двойных кавычках, правый раскрывается в одинарных кавычках.

Charles Duffy 28.02.2019 22:01
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
3
4
121
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

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

$ jq -Rr 'split("\t") | .[1] |= fromjson.catId | join("\t")' input.log

Не могли бы вы объяснить, что делает |=?

test 28.02.2019 21:57

@test: Assignments = просто берет значение справа и обновляет поле слева. Контекст для этого значения не изменился, что означает, что «ввод» для значения — это тот же ввод в LHS. Использование |= изменяет контекст, так что «вводом» для значения является значение LHS.

Jeff Mercado 28.02.2019 22:02

@Jeff, можно ли добавить еще один элемент массива? псевдокод: .[1] |= fromjson.catId .[2] = fromjson.another'

test 28.02.2019 22:24

@test: Вы должны уметь: ... | . += [$yourItem] | .... Я лично предпочитаю: ... | [.[], $yourItem] | ...

Jeff Mercado 28.02.2019 22:32

@Джефф. не может заставить это работать. Работает со статической строкой, такой как ... | [.[], "foo"] | ..., но не с динамической ... | [.[], fromjson.id] | ...

test 28.02.2019 23:04

@test: вам нужно знать текущий контекст. В вашем примере массив элементов является текущим «входом», поэтому использование fromjson в этом массиве будет ошибкой. это работает только в ответе выше, потому что мы изменили контекст, чтобы он был вторым элементом в массиве (.[1] |= ...), если вы хотите добавить несколько значений из этого одного объекта, вы захотите сделать это в рамках этого обновления-назначения. например, ... | .[1:] |= (.[0] | fromjson | [.catId, .img]) | ... (обратите внимание на изменение в LHS)

Jeff Mercado 28.02.2019 23:13

Просто добавьте, почему ваш код не работает, поскольку предыдущие ответы лучше. В вашем случае $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

$

Другие вопросы по теме