简体   繁体   中英

How can I get a JSON field value without `jq`?

I'm trying to extract a value from a JSON in a limited environment where I cannot install any tools or download anything from the internet. The tools that I have available on the environment are the basic ones provided by busybox such as: awk , grep , and sed . No compilers or interpreters like Perl and Python are available.

The JSON I'm trying to parse has a fixed scheme but it can be formatted in any valid way and I always need to get the value of the field tag .

Examples of possible JSONs:

{"version":1,"name":"2","tag":"3"}
{
    "version": 1,
    "tag":    "3",
    "name"   :"2"
}

This might work for you (GNU sed):

sed -nE '$!{:a;N;$!ba;s/\n//g;s/"tag":[^"]*"([^"]*)"/\n\1\nTAG/g};/^[^\n]*\nTAG/P;D' file

This slurps the file into memory, removes all newlines, reverses tag value and tag onto separate consecutive lines and prints the first of those two lines.

Alternative, using tr , grep and sed :

tr -d '\n' <file | grep -o '"tag":[^"]*"[^"]*"' | sed -E 's/".*".*"(.*)"/\1/'

This will work for the data format you have (ie not for the possible full JSON syntax) using any awk in any shell on every UNIX box:

$ cat tst.awk
{ rec = rec $0 }
END {
    gsub(/^[ \t]*[{][ \t]*|[ \t]*[}][ \t]*$/,"",rec)
    while ( match(rec,/"[^"]+"[ \t]*:[ \t]]*("[^"]*"|[^,]*)/) ) {
        key = val = substr(rec,RSTART+1,RLENGTH-1)
        sub(/".*/,"",key)
        sub(/[^"]*"[ \t]]*:[ \t]*/,"",val)
        f[key] = val
        rec = substr(rec,RSTART+RLENGTH)
    }
    print f[k]
}

$ echo '{"version":1,"name":"2","tag":"3"}' | awk -v k=tag -f tst.awk
"3"

$ cat file
{
    "version": 1,
    "tag":    "3",
    "name"   :"2"
}

$ awk -v k=tag -f tst.awk file
"3"

You can easily output whatever value you like:

$ awk -v k=name -f tst.awk file
"2"

$ awk -v k=version -f tst.awk file
1

and it'd be trivial to modify to output multiple values in any order you like, or only output the value of one key if it's in a range or based on relationships between other keys values, etc., etc. For example:

$ cat tst.awk
{ rec = rec $0 }
END {
    split(keys,ks,/,/)
    gsub(/^[ \t]*[{][ \t]*|[ \t]*[}][ \t]*$/,"",rec)
    while ( match(rec,/"[^"]+"[ \t]*:[ \t]*("[^"]*"|[^,]*)/) ) {
        key = val = substr(rec,RSTART+1,RLENGTH-1)
        sub(/".*/,"",key)
        sub(/[^"]*"[ \t]*:[ \t]*/,"",val)
        f[key] = val
        rec = substr(rec,RSTART+RLENGTH)
    }
    if ( (f["version"] > 0) && (f["name"] != f["tag"]) ) {
        for (i=1; i in ks; i++) {
            k = ks[i]
            print k, f[k]
        }
    }
}

$ awk -v keys=tag,version,name -f tst.awk file
tag "3"
version 1
name "2"

It'd also be trivial to strip the quotes from around the values if you don't want them by just adding gsub(/^"|"$/,"",val) in the loop right above f[key] = val .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM