Используйте IFS$’n’ для чтения -r jq в несколько переменных

#json #bash #while-loop #jq #ifs

Вопрос:

В настоящее время у меня есть следующий код, который работает так, как я этого хочу.

 foo='
[{
    "name": "e2e (control-plane, true, true, true, ipv4, IPv4, true, false)",
    "failed_step": {
        "name": "Run Tests",
        "conclusion": "failure",
        "number": 11
    }
}, {
    "name": "e2e (control-plane, true, true, true, ipv4, IPv4, true, false)",
    "failed_step": {
        "name": "Generate Test Report",
        "conclusion": "failure",
        "number": 13
    }
}]'

echo "$foo" | jq -r '.[] | .name, .failed_step.name, .failed_step.number' | while 
    read -r job amp;amp; read -r step amp;amp; read -r number; do
        echo "job = $job";
        echo "step = $step";
        echo "number = $number";
done
 

который выводит следующий желаемый вывод:

 job = e2e (control-plane, true, true, true, ipv4, IPv4, true, false)
step = Run Tests
number = 11
job = e2e (control-plane, true, true, true, ipv4, IPv4, true, false)
step = Generate Test Report
number = 13
 

Однако мой вопрос заключается в том, есть ли способ сделать это с помощью IFS, чтобы избежать 3 отдельных инструкций чтения? Я придумал следующее, однако результат, который он генерирует, не совсем правильный. Похоже, что он считывается только в первую переменную.

 echo "$foo" | jq -r '.[] | .name, .failed_step.name, .failed_step.number' | while IFS=

выход:

 job = e2e (control-plane, true, true, true, ipv4, IPv4, true, false)
step = 
number = 
job = Run Tests
step = 
number = 
job = 11
step = 
number = 
job = e2e (control-plane, true, true, true, ipv4, IPv4, true, false)
step = 
number = 
job = Generate Test Report
step = 
number = 
job = 13
step = 
number = 
 

Я чувствую, что должен быть способ сделать это, однако я занимался этим некоторое время безрезультатно.

Ответ №1:

Вам не нужна while петля. Просто отформатируйте его с помощью команды jq:

 echo "$foo" | jq -j '.[] | "job = ", .name, "nstep = ", .failed_step.name, "nnumber = ", .failed_step.number, "n"'
 

Это дает тот же результат, который вы хотите:

 $ echo "$foo" | jq -j '.[] | "job = ", .name, "nstep = ", .failed_step.name, "nnumber = ", .failed_step.number, "n"'
job = e2e (control-plane, true, true, true, ipv4, IPv4, true, false)
step = Run Tests
number = 11
job = e2e (control-plane, true, true, true, ipv4, IPv4, true, false)
step = Generate Test Report
number = 13
$
 

Комментарии:

1. Определенно существует несколько решений для решения вопроса ОП. Но это, пожалуй, самый эффективный ответ 🙂

Ответ №2:

Вместо того , чтобы пытаться использовать n , возможно, настройте jq разделитель с помощью вкладок. Что-то вроде:

 jq -r '.[] | .name   "t"   .failed_step.name   "t"   (.failed_step.number | tostring)'
 

Тогда вы можете сделать while IFS=$'t' read job step number; do ...

n'
read -r job step number; do
echo "job = $job";
echo "step = $step";
echo "number = $number";
done
выход:


Я чувствую, что должен быть способ сделать это, однако я занимался этим некоторое время безрезультатно.

Ответ №1:

Вам не нужна while петля. Просто отформатируйте его с помощью команды jq:


Это дает тот же результат, который вы хотите:


Комментарии:

1. Определенно существует несколько решений для решения вопроса ОП. Но это, пожалуй, самый эффективный ответ 🙂

Ответ №2:

Вместо того , чтобы пытаться использовать n , возможно, настройте jq разделитель с помощью вкладок. Что-то вроде:


Тогда вы можете сделать while IFS=$'t' read job step number; do ...