17

I would like to use python to parse JSON in batch scripts, for example:

HOSTNAME=$(curl -s "$HOST" | python ?)

Where the JSON output from curl looks like:

'{"hostname":"test","domainname":"example.com"}'

How can I do this with a single line python command?

tripleee
  • 175,061
  • 34
  • 275
  • 318
Chris Snow
  • 23,813
  • 35
  • 144
  • 309
  • 2
    Much easier to use something like `jq` from the command line, which is dedicated to parsing JSON and so has a cleaner design: `HOSTNAME=$(curl -s $HOST | jq -r '.hostname')`. – chepner Jul 20 '16 at 17:39
  • 2
    Down voters, please state why you are down voting. It's difficult to improve questions if you don't know what's wrong with them. – Chris Snow Jul 20 '16 at 17:41
  • 2
    @chepner true, but I don't have and can't install jq on the host in question, but I do have python and the json module. – Chris Snow Jul 20 '16 at 17:43
  • 1
    For what purpose do you require the Python code to be "a single line"? – Jongware Jul 23 '16 at 10:01
  • 2
    It's much easier to work with single line commands in a batch script. Multi line Python statements that require Python indentation are difficult to integrate into scripts using pipes and redirects without having to put the Python statements into a separate file as a Python script. – Chris Snow Jul 23 '16 at 10:13
  • 1
    Doing this in Python is an excellent question and doesn't deserve a downvote. (Also, handy command-line utilities like `jq` exist, so any Python solution will be somewhat more flabby than `jq`). – smci Jul 31 '17 at 18:37

3 Answers3

21

Based on the JSON below being returned from the curl command ...

'{"hostname":"test","domainname":"example.com"}'

You can then use python to extract the hostname using the python json module:

HOSTNAME=$(curl -s "$HOST" |
  python -c \
    'import json,sys;print(json.load(sys.stdin)["hostname"])')

Note that I have split the line using a \ to make it more readable on stackoverflow. I've also simplified the command based on chepner's comment.

Original source: Parsing JSON with Unix tools

See also: https://wiki.python.org/moin/Powerful%20Python%20One-Liners

Mathias Bynens
  • 144,855
  • 52
  • 216
  • 248
Chris Snow
  • 23,813
  • 35
  • 144
  • 309
  • 1
    For a one-liner, I wouldn't bother with the intermediate variable `obj`: `python -c 'import json,sys;print json.load(sys.stdin)["hostname"]`. – chepner Jul 20 '16 at 17:50
  • 2
    For python3: `python3 -c 'import json,sys; print(json.load(sys.stdin)["hostname"])'`. Same thing but with parens for print – Xiao Dec 07 '20 at 02:20
  • This answer, while technically correct, is not conveniently formatted with executable code snippets. For instance most people are more interested in parsing the JSON, than in making a curl call to a service running on particular host. (I tried to edit it for clarity, but was rejected.) – MarkHu Feb 23 '21 at 19:41
12
echo '{"hostname":"test","domainname":"example.com"}' | python -m json.tool
hustljian
  • 965
  • 12
  • 9
6

Since Python is multiplatform, is important to note differences between Linux and Windows, especially because of how they treat double-quotes/single-quotes differently.

Second, some previous answers are a little bit obsolete: in python2, print without parentheses was permitted. Nevertheless, in python3, print must be between parentheses.

Linux (bash)

It doesn't matter how you put double/single quotes. Json can be parsed in both ways with "keys" or 'keys'

HOSTNAME=$(curl -s "$HOST" |
  python3 -c 'import json,sys;print(json.load(sys.stdin)["hostname"])')

It also works: (pay attention at single/double quote at key)

HOSTNAME=$(curl -s "$HOST" |
  python3 -c "import json,sys;print(json.load(sys.stdin)['hostname'])")

Windows (powershell)

Keys in json MUST be between single quotes. Only the following syntax is accepted.
The ConvertTo-Json function generates object and works with keys between single quotes.

$HOSTNAME=(Invoke-RestMethod $HOST | `
  ConvertTo-Json | `
  python3 -c "import json,sys; print(json.load(sys.stdin)['hostname'])")
tripleee
  • 175,061
  • 34
  • 275
  • 318
Alejandro Galera
  • 3,445
  • 3
  • 24
  • 42