Mowgli
Mowgli

Reputation: 143

Read a json file and grep a string from matching pattern using bash

I am trying to parse below big json file using bash

//part of json file
{"name": "Jenkins", "version": "Jenkins-2.22"},
{"name": "FitNesse", "version": "FitNesse-2.1"},
{"name": "Quint","version": "Quint-2.12"},
{"name": "Otto","version": "Otto-1.0"},
{"name": "Gradle","version": "Gradle-1.1"}

I am able read the line matching 'version' from json file

while read line; do
  if [[ $line =~ "version" ]] ; then
    echo $line; fi
done < $manifestfile

I want to store the values[Jenkins-2.22, FitNesse-2.1, Quint-2.12, Otto-1.0, Gradle-1.1] in array in my while loop

need help with tweaking my above code

Upvotes: 1

Views: 5171

Answers (4)

asayah
asayah

Reputation: 1

Use JQ for parsing your Json easily, just install JQ, then use :

if you have a json array, and in every element you have the field version, you can use :

 cat myJsonFile | jq '.[].version'

That will return a list of versions

If you want to process line by line use

while read line; do
  if [[ $line =~ "version" ]] ; then
    echo $line | jq .[] | jq ."version" ; fi
done < $manifestfile

Upvotes: 0

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

jq is a proper tool to manipulate JSON data in Unix shell.

Let's say test.json file contains:

[
{"name": "Jenkins", "version": "Jenkins-2.22"},
{"name": "FitNesse", "version": "FitNesse-2.1"},
{"name": "Quint","version": "Quint-2.12"},
{"name": "Otto","version": "Otto-1.0"},
{"name": "Gradle","version": "Gradle-1.1"}
]

test_json.sh script (simplified version):

#!/bin/bash
versions=$(jq '.[] | .version' test.json)
versions_arr=($versions)  # contains an array of `version` key values

I must warn that the above approach ($versions) (creating an array upon string splitting) may fail if the string $versions has globbing characters in it.


The more "steady" approach would be using built-in read command with -a option to read the data wordwise into the specified array:

test_json.sh script ("steady" version):

#!/bin/bash
versions=$(jq '.[] | .version' test.json)
read -a versions_arr <<< $versions  # read `version` key values into array

Now, versions_arr is an array of version key values.
To print for e.g. the second array value you would do:

echo ${versions_arr[1]} 

The output:

"FitNesse-2.1"

Upvotes: 1

mklement0
mklement0

Reputation: 438283

Assuming that the sample input above is inside a JSON array in file file.json, i.e.:

[
  {"name": "Jenkins", "version": "Jenkins-2.22"},
  {"name": "FitNesse", "version": "FitNesse-2.1"},
  {"name": "Quint","version": "Quint-2.12"},
  {"name": "Otto","version": "Otto-1.0"},
  {"name": "Gradle","version": "Gradle-1.1"}
]

Note: The only change required to make the commands below work in Bash 3.x too is to replace readarray -t versions with IFS=$'\n' read -d '' -ra versions

Using Bash 4.x and jq:

jq must be installed first, but that's well worth the effort, if feasible: it enables sophisticated, robust JSON parsing.

# Extract the version numbers and read them into a Bash array.
readarray -t versions < <(jq -r '.[].version' file.json)

# Print the array.
printf '%s\n' "${versions[@]}"

The above yields:

Jenkins-2.22
FitNesse-2.1
Quint-2.12
Otto-1.0
Gradle-1.1

Using Bash 4.x and awk:

If you cannot install jq, the following awk solution is an alternative, but note that it is much less robust and relies on the JSON to be formatted exactly as above.
This warning applies to any solution using standard utilities (awk, grep, sed, ...) - only a dedicated JSON parser will work robustly.

readarray -t versions < <(awk -F\" 'NF>1 { print $(NF-1) }' file.json)

# Print the array.
printf '%s\n' "${versions[@]}"

Upvotes: 3

Michael
Michael

Reputation: 5335

sed -n 's/.*"\([^"]*\)"}.*/\1/p' <file>

Upvotes: 2

Related Questions