Как форматировать строку JSON в виде таблицы с помощью jq?

Просто начал с Bash скриптинга и наткнулся на jq, чтобы работать с JSON.

Мне нужно преобразовать строку JSON, как показано ниже, в таблицу для вывода в терминале.

[{
    "name": "George",
    "id": 12,
    "email": "[email protected]"
}, {
    "name": "Jack",
    "id": 18,
    "email": "[email protected]"
}, {
    "name": "Joe",
    "id": 19,
    "email": "[email protected]"
}]

Что я хочу отображать в терминале:

ID        Name
=================
12        George
18        Jack
19        Joe

Обратите внимание, что я не хочу отображать свойство электронной почты для каждой строки, поэтому команда jq должна включать некоторую фильтрацию. Следующее дает мне простой список имен и идентификаторов:

list=$(echo "$data" | jq -r '.[] | .name, .id')
printf "$list"

Проблема в том, что я не могу отображать его как таблицу. Я знаю, что jq имеет некоторые параметры форматирования, но не так хорош, как параметры, которые у меня есть при использовании printf. Я думаю, что хочу получить эти значения в массиве, который затем я смогу прокрутить сам, чтобы сделать форматирование...? То, что я пробовал, дало мне разные результаты, но я никогда этого не делал.

Может ли кто-нибудь указать мне в правильном направлении?

Ответ 1

Почему бы не что-то вроде:

echo '[{
    "name": "George",
    "id": 12,
    "email": "[email protected]"
}, {
    "name": "Jack",
    "id": 18,
    "email": "[email protected]"
}, {
    "name": "Joe",
    "id": 19,
    "email": "[email protected]"
}]' | jq -r '.[] | "\(.id)\t\(.name)"'

Вывод

12  George
18  Jack
19  Joe

Изменить 1: для мелкозернистого форматирования используйте такие инструменты, как awk

 echo '[{
    "name": "George",
    "id": 12,
    "email": "[email protected]"
}, {
    "name": "Jack",
    "id": 18,
    "email": "[email protected]"
}, {
    "name": "Joe",
    "id": 19,
    "email": "[email protected]"
}]' | jq -r '.[] | [.id, .name] | @csv' | awk -v FS="," 'BEGIN{print "ID\tName";print "============"}{printf "%s\t%s%s",$1,$2,ORS}'
ID  Name
============
12  "George"
18  "Jack"
19  "Joe"

Редактировать 2: В ответ на

Я не могу получить переменную, содержащую массив прямо из jq?

Почему нет?

Немного вовлеченный пример (фактически измененный от вашего), где электронная почта изменена на массив, демонстрирует это

echo '[{
    "name": "George",
    "id": 20,
    "email": [ "[email protected]" , "[email protected]" ]
}, {
    "name": "Jack",
    "id": 18,
    "email": [ "[email protected]" , "[email protected]" ]
}, {
    "name": "Joe",
    "id": 19,
    "email": [ "[email protected]" ]
}]' | jq -r '.[] | .email'

Вывод

[
  "[email protected]",
  "[email protected]"
]
[
  "[email protected]",
  "[email protected]"
]
[
  "[email protected]"
]

Ответ 2

Использование фильтра @tsv может многое рекомендовать, главным образом потому, что он обрабатывает множество "краевых случаев" стандартным образом:

.[] | [.id, .name] | @tsv

Добавление заголовков можно сделать так:

jq -r '["ID","NAME"], ["--","------"], (.[] | [.id, .name]) | @tsv'

Результат:

ID  NAME
--  ------
12  George
18  Jack
19  Joe

Ответ 3

Если значения не содержат пробелов, это может быть полезно:

read -r -a data <<<'name1 value1 name2 value2'

echo "name value"
echo "=========="

for ((i=0; i<${#data[@]}; i+=2)); do
  echo ${data[$i]} ${data[$((i+1))]}
done

Вывод

name value
==========
name1 value1
name2 value2