Extract 2 fields from string with search

Viewed 70

I have a file with several lines of data. The fields are not always in the same position/column. I want to search for 2 strings and then show only the field and the data that follows. For example:

{"id":"1111","name":"2222","versionCurrent":"3333","hwVersion":"4444"}

{"id":"5555","name":"6666","hwVersion":"7777"}

I would like to return the following:

"id":"1111","hwVersion":"4444"

"id":"5555","hwVersion":"7777"

I am struggling because the data isn't always in the same position, so I can't chose a column number. I feel I need to search for "id" and "hwVersion" Any help is GREATLY appreciated.

2 Answers

Since the data looks like a mapping objects and even corresponding to a JSON format, something like this should do, if you don't mind using Python (which comes with JSON) support:

import json

def get_id_hw(s):
    d = json.loads(s)
    return '"id":"{}","hwVersion":"{}"'.format(d["id"], d["hwVersion"])

We take a line of input string into s and parse it as JSON into a dictionary d. Then we return a formatted string with double-quoted id and hwVersion strings followed by column and double-quoted value of corresponding key from the previously obtained dict.

We can try this with these test input strings and prints:

# These will be our test inputs.
s1 = '{"id":"1111","name":"2222","versionCurrent":"3333","hwVersion":"4444"}'
s2 = '{"id":"5555","name":"6666","hwVersion":"7777"}'

# we pass and print them here
print(get_id_hw(s1))
print(get_id_hw(s2))

But we can just as well iterate over lines of any input.

If you really wanted to use awk, you could, but it's not the most robust and suitable tool:

awk '{ i = gensub(/.*"id":"([0-9]+)".*/, "\\1", "g")
       h = gensub(/.*"id":"([0-9]+)".*/, "\\1", "g")
       printf("\"id\":\"%s\",\"hwVersion\":\"%s\"\n"), i, h}' /your/file

Since you mention position is not known and assuming it can be in any order, we use one regex to extract id and the other to get hwVersion, then we print it out in given format. If the values could be something other then decimal digits as in your example, the [0-9]+ but would need to reflect that.

And for the fun if it (this preserves the order) if entries from the file, in sed:

sed -e 's#.*\("\(id\|hwVersion\)":"[0-9]\+"\).*\("\(id\|hwVersion\)":"[0-9]\+"\).*#\1,\3#' file

It looks for two groups of "id" or "hwVersion" followed by :"<DECIMAL_DIGITS>".

Totally agree with @KamilCuk. More specifically

jq -c '{id: .id, hwVersion: .hwVersion}' <<< '{"id":"1111","name":"2222","versionCurrent":"3333","hwVersion":"4444"}'

Outputs:

{"id":"1111","hwVersion":"4444"}

Not quite the specified output, but valid JSON

More to the point, your input should probably be processed record by record, and my guess is that a two column output with "id" and "hwVersion" would be even easier to parse:

cat << EOF | jq -j '"\(.id)\t\(.hwVersion)\n"'
{"id":"1111","name":"2222","versionCurrent":"3333","hwVersion":"4444"}
{"id":"5555","name":"6666","hwVersion":"7777"}
EOF

Outputs:

1111    4444
5555    7777
Related