Используя 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.'
Другие вопросы по тегам