1

I currently have the following code which works as I want it to.

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 && read -r step && read -r number; do
        echo "job = $job";
        echo "step = $step";
        echo "number = $number";
done

which outputs the following desired output:

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

However, my question is, is there a way to do this using IFS to avoid 3 separate read statements? I came up with the following, however, the output it generates is not quite right. It looks like it only reads into the first variable.

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

output:

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 = 

I feel like there has to be a way to do this, however I've been at it for a while with no success.

2 Answers2

2

You don't need a while loop. Just format it with the jq command:

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

This produces the same output that you want:

$ 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
$
Luis Guzman
  • 996
  • 5
  • 8
  • There are definitely several solutions to address the OP's question. But this is probably the most effective answer :) – ErikMD Jul 29 '21 at 22:20
2

Rather than trying to use \n, perhaps tweak the jq to separate with tabs. Something like:

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

Then you can do while IFS=$'\t' read job step number; do ...

William Pursell
  • 204,365
  • 48
  • 270
  • 300