Saving a piped value went wrong

I installed jq to handle some JSON with bash.
But somehow piping the JSON string to jq in combination with saving it’s output to another variable went wrong.

TEST='{"foo": "bar"}'
PB_SIG=$TEST | jq '.foo'
echo $PB_SIG

It outputs just the whole TEST JSON string. Somebody?

Asked By: Milkmannetje

||

Try this on the second line:

PB_SIG=`echo $TEST | jq '.foo'`

The two problems I see is that you need to echo the $TEST variable’s value through the pipe and that you need to capture the output of the piped command.

Answered By: John

Use this with bash:

TEST='{"foo": "bar"}'
PB_SIG=$(jq '.foo' <<< "$TEST")
echo "$PB_SIG"

Output:

"bar"
Answered By: Cyrus

There are a few issues in your code. The immediate issue causing you your present problem is that you are using the wrong syntax. To save the output of a command or a pipeline of commands in a variable, you likely want to use a command substitution, variable=$(some command).

A second issue is your use of $TEST unquoted. When the variable expansion is unquoted, the shell will split its value on spaces, tabs, and newlines (the contents of the IFS variable), and then apply filename globbing to each of the split-up bits. This means that a JSON document like {"foo": "a * bar"} may end up outputted together with all the visible filenames in the current directory.

Yet another issue is your use of echo to output variable data. If the JSON document contained a string with an encoded tab (t) or newline (n), then the echo may cause these to be expanded to literal tabs and newlines. The following question with answers talks more in-depth about this: Why is printf better than echo?

Since you want to pass your JSON document from a shell variable to a jq expression to extract the value of the top-level foo key, we may do this like so:

document='{"foo": "bar"}'
signature=$( jq -n -r --argjson data "$document" '$data.foo' )

This creates a jq variable called data containing the JSON structure found in the document shell variable. The jq command then extracts the foo key’s value from this without reading any data from any file or data stream (since -n is used). The extracted string is decoded (since -r is used) and stored in the shell variable signature.

To output the value of the signature variable:

printf '%sn' "$signature"

… but if all you wanted to do was to output the value, then there is no point in first storing it in a shell variable. Instead, you would let jq output the value directly by omitting the command substitution:

document='{"foo": "bar"}'
jq -n -r --argjson data "$document" '$data.foo'
Answered By: Kusalananda
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.