544

I have this Json

{
    "users": [
        {
            "first": "Stevie",
            "last": "Wonder"
        },
        {
            "first": "Michael",
            "last": "Jackson"
        }
    ]
}

Using jq I'd like to display first and last name serially. Like so -

Stevie Wonder
Michael Jackson

This is how far I have gotten -

jq '.users[].first, .users[].last'

But it displays

"Stevie"
"Michael"
"Wonder"
"Jackson"

Notice the following:

  1. The double quotes that I do not want.
  2. The carriage return that I do not want.
  3. It's jumbled up. My query displays all the first names first, and then all the last names. However, I want first-last, first-last pair.
0

9 Answers 9

755

I recommend using String Interpolation:

jq '.users[] | "\(.first) \(.last)"'

We are piping down the result of .users[] to generate the string ".first .last" using string interpolation. \(foo) syntax is used for string interpolation in jq. So, for the above example, it becomes "Stevie Wonder" (".users[].first .users[].second" working elementwise) and "Michael Jackson".

jq reference: String interpolation

Sign up to request clarification or add additional context in comments.

6 Comments

this is far better if your data are numbers
An explanation of the syntax would make this answer more useful.
A good answer should never just have an explanation in a link. Anything can happen to the website that is linked, and then people are left copying code that they don't understand.
Add -r switch if you don't want the output to be wrapped in quotes.
to append name or id with value jq '.[] | "id=\(.id) name=\(.name)"')
|
397

You can use addition to concatenate strings.

Strings are added by being joined into a larger string.

jq '.users[] | .first + " " + .last'

The above works when both first and last are string. If you are extracting different datatypes(number and string), then we need to convert to equivalent types. Referring to solution on this question. For example.

jq '.users[] | .first + " " + (.number|tostring)'

4 Comments

To eliminate the JSON quotation marks, invoke jq with the -r option, e.g. jq -r '.users[] | .first + " " + .last'
+1, but for my use case, I'm trying to format two numbers onto the same row. This approach fails because it can't add " " to a number. Eric's answer gives a better result for this case.
@Synesso: (.numA|tostring) + " " + (.numB|tostring) should work. Or use string interpolation instead: "\(.numA) \(.numB)".
When I did jq '.users[] | .first + " " + .last', it worked very well, but caused a newline between the value of .first and .last. I changed the " " to "@" and then did a sed 's/@/ /g' on the output to get "John Smith" as the output. Something like this: jq '.users[] | .first + "@" + .last' | sed 's/@/ /g'
94

In addition to what others have suggested, I think that two options are worth mentioning.

Print as CSV/TSV

$ cat file.json | jq -r '.users[] | [.first, .last] | @tsv'
Stevie  Wonder
Michael Jackson
cat file.json | jq -r '.users[] | [.first, .last] | @csv'
"Stevie","Wonder"
"Michael","Jackson"

The first expression, .users[], unnests the objects from the outer-most array as in the code given in the question. The next expression, [.first, .last], creates a new array of the values for each input object, and the final expression uses the built-in functions @tsv and @csv to print all input arrays as tab-separated and comma-seperated values, respectively.

Print as JSON values

Similarly, it is possible to construct JSON values again, which is interesting if you just want to keep a subset of the fields:

$ cat file.json | jq -c '.users[] | {first}'
{"first":"Stevie"}
{"first":"Michael"}

Comments

88
jq '.users[]|.first,.last' | paste - -

N fields per jq record == N dashes in paste.

1 Comment

this one allows to print array-fields with good formatting, unlike the other string-centric answers. thx
22

my approach will be (your json example is not well formed.. guess thats only a sample)

jq '.Front[] | [.Name,.Out,.In,.Groups] | join("|")'  front.json  > output.txt

returns something like this

"new.domain.com-80|8.8.8.8|192.168.2.2:80|192.168.3.29:80 192.168.3.30:80"
"new.domain.com -443|8.8.8.8|192.168.2.2:443|192.168.3.29:443 192.168.3.30:443"

and grep the output with regular expression.

2 Comments

I wonder what this has to do with the question...? Also — why do you claim that the JSON example given by the OP is 'not well formed'? It looks great to me — and to syntax-checking tools, like, aye, jq itself. Also: can you show the contents of `front.json?
The comment was made in 2020, and someone edited the question in 2021. What you are seeing is the latest version of the question.
18

This will produce an array of names

> jq '[ .users[] | (.first + " " + .last) ]' ~/test.json

[
  "Stevie Wonder",
  "Michael Jackson"
]

Comments

17

While both of the above answers work well if key,value are strings, I had a situation to append a string and integer (jq errors using the above expressions)

Requirement: To construct a url out below json

pradeep@seleniumframework>curl http://192.168.99.103:8500/v1/catalog/service/apache-443 | jq .[0]
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   251  100   251    0     0   155k      0 --:--:-- --:--:-- --:--:--  245k
{
  "Node": "myconsul",
  "Address": "192.168.99.103",
  "ServiceID": "4ce41e90ede4:compassionate_wozniak:443",
  "ServiceName": "apache-443",
  "ServiceTags": [],
  "ServiceAddress": "",
  "ServicePort": 1443,
  "ServiceEnableTagOverride": false,
  "CreateIndex": 45,
  "ModifyIndex": 45
}

Solution:

curl http://192.168.99.103:8500/v1/catalog/service/apache-443 |
jq '.[0] | "http://" + .Address + ":" + "\(.ServicePort)"'

2 Comments

note that escaping the closing parenthesis is not needed, and would err.
@nymo: That's not escaping. \(...) is string interpolation. Here it turns numeric .ServicePort into string. Interpolation could be used in place of the + signs to make this solution shorter.
6

I got pretty close to what I wanted by doing something like this

cat my.json | jq '.my.prefix[] | .primary_key + ":", (.sub.prefix[] | "    - " + .sub_key)' | tr -d '"' 

The output of which is close enough to yaml for me to usually import it into other tools without much problem. (I am still looking for a way to basicallt export a subset of the input json)

1 Comment

This sort of works in my case, just drop the | tr -d '"' at the end, and add -r option to jq.
2

A little bit more steps but I noticed no one here mentions join(). join() only works for array so you need to construct one. To eliminate double quotes, use -r:

echo $JSON | jq -r '.users[] | [.first,.last] | join(" ")'

, means applying filter to the previous step's output with such order, so you .first then you get .last and create an array.

A small test does not show any performance degrading.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.