Используя jq для назначения нескольких выходных переменных
Я пытаюсь использовать jq
для анализа информации из API TVDB. Мне нужно вытащить пару полей и присвоить значения переменным, которые я могу продолжать использовать в моем bash
скрипт. Я знаю, что могу легко назначить вывод одной переменной через bash с variable="$(command)"
но мне нужен вывод для создания нескольких переменных, и я не хочу использовать несколько команд.
Я прочитал эту документацию:
https://stedolan.github.io/jq/manual/v1.5/
но я не знаю, имеет ли это отношение к тому, что я пытаюсь сделать.
jq '.data'
производит следующий вывод:
[
{
"absoluteNumber": 51,
"airedEpisodeNumber": 6,
"airedSeason": 4,
"airedSeasonID": 680431,
"dvdEpisodeNumber": 6,
"dvdSeason": 4,
"episodeName": "We Will Rise",
"firstAired": "2017-03-15",
"id": 5939660,
"language": {
"episodeName": "en",
"overview": "en"
},
"lastUpdated": 1490769062,
"overview": "Clarke and Roan must work together in hostile territory in order to deliver an invaluable asset to Abby and her team."
}
]
Я старался jq '.data | {episodeName:$name}'
а также jq '.data | .episodeName as $name'
просто чтобы попытаться заставить работать. Я не понимаю документацию или даже если это то, что я ищу. Есть ли способ сделать то, что я пытаюсь сделать?
3 ответа
Вы можете использовать отдельные переменные с read
:
IFS='|' read var1 var2 var3 var4 < <(curl '......' | jq -r '.data |
map([.absoluteNumber, .airedEpisodeNumber, .episodeName, .overview] |
join("|")) | join("\n")')
Или используйте массив как:
set -f; IFS='|' data=($(curl '......' | jq -r '.data |
map([.absoluteNumber, .airedEpisodeNumber, .episodeName, .overview] |
join("|")) | join("\n")')); set +f
absoluteNumber
, airedEpisodeNumber
, episodeName
& overview
соответственно ${data[0]}
, ${data[1]}
, ${data[2]}
, ${data[3]}
, set -f
а также set +f
используются, чтобы соответственно отключить и включить globbing.
Для jq
часть, все необходимые поля сопоставлены и разделены '|'
персонаж с join("|")
Если вы используете JQ < 1,5, вам придется конвертировать число в строку с tostring
для каждого номера поля, например:
IFS='|' read var1 var2 var3 var4 < <(curl '......' | jq -r '.data |
map([.absoluteNumber|tostring, .airedEpisodeNumber|tostring, .episodeName, .overview] |
join("|")) | join("\n")')
jq всегда создает поток с нулем или более значений. Например, чтобы получить два значения, соответствующие "episodeName" и "id", вы можете написать:
.data[] | ( .episodeName, .id )
Для ваших целей может быть полезно использовать параметр командной строки -c, чтобы каждое выходное значение JSON было представлено в одной строке. Вы также можете использовать параметр командной строки -r, который удаляет крайние кавычки из каждого выходного значения, являющегося строкой JSON.
Для дальнейших изменений, пожалуйста, смотрите jq FAQ https://github.com/stedolan/jq/wiki/FAQ, например, вопрос:
В: Как можно преобразовать поток JSON-текстов, созданных jq, в массив bash с соответствующими значениями?
Экспериментальное преобразование цитируемого ввода OP (tv.dat) в серию bash
переменные (и массив). jq
код в основном заимствован здесь и там, но я не знаю, как получить jq
развернуть массив в массиве, поэтому sed
код делает это, (это хорошо только для одного уровня, но так bash
массивы):
jq -r ".[] | to_entries | map(\"DAT_\(.key) \(.value|tostring)\") | .[]" tv.dat |
while read a b ; do echo "${a,,}='$b'" ; done |
sed -e '/{.*}/s/"\([^"]*\)":/[\1]=/g;y/{},/() /' -e "s/='(/=(/;s/)'$/)/"
Выход:
dat_absolutenumber='51'
dat_airedepisodenumber='6'
dat_airedseason='4'
dat_airedseasonid='680431'
dat_dvdepisodenumber='6'
dat_dvdseason='4'
dat_episodename='We Will Rise'
dat_firstaired='2017-03-15'
dat_id='5939660'
dat_language=([episodeName]="en" [overview]="en")
dat_lastupdated='1490769062'
dat_overview='Clarke and Roan must work together in hostile territory in order to deliver an invaluable asset to Abby and her team.'