Parsing and Editing a json file with bash script

I am trying to automate editing of a json file using bash script.

The file I initially receive is

{
  "appMap": {
    "URL1": {
      "name": "a"
    },
    "URL2": {
      "name": "b"
    },
  "URL3": {
      "name": "c"
    },
}

WHat I would like to do is replace URL1,URL2,URL3 with URL4,URL5,URL6.

I do not want to use a sed command like:

sed -i "s/URL1/URL4/g" <file>

But I want to parse through it and change values based on "name".

Is this something that is possible using bash ? Or do I need to look into perl or python ?

Hello Juniad Subhani,

Could you please try following and let me know if this helps.

perl -pi -e 's/URL1/URL4/g;s/URL2/URL5/g;s/URL3/URL6/g'  Input_file

Wanted to add here this will change Input_file with the new values.

Thanks,
R. Singh

Some more/refined details, please! I guess you don't want to modify based on "name" (the constant string), but on name's value, i.e. "a", "b", or "c", and all of this just in the "appMap" section?

Hello RudiC,

Yes its more like if "name" is "a" , use URL4
If "name" is "b", use URL5
If "name" is "c", use URL6

Here is an awk approach:-

awk -F'[" ]' '
        BEGIN {
                A["a"] = "URL4"
                A["b"] = "URL5"
                A["c"] = "URL6"
        }
        /URL/ {
                s = $0
                getline
                if ( $(NF-1) in A )
                        sub( /URL[0-9]+/, A[$(NF-1)], s )
                print s
        }
        1
' file.json

Well, although a parser is not simply done but usually an intricate piece of software, here is

  • a bash script
  • replacing ALL kind of URLs (abc.com; def.org; ghi.de; ...)
  • only in "appMar" section
    As the URL can assume any shape, we can't rely on a string constant ("URLnn") but need to check for the file structure (the URL is the first entry in the second nesting level).

Try

#!/bin/bash
#
TGSCT=0
LEVEL=0
URL=""

declare -A RP
RP["a"]=XYZ.com                                         # set up replacement URLs
RP["b"]=YZX.org
RP["c"]=ZXY.biz

while IFS="" read LN                                    # don't destroy original line
 do     IFS=": " read P1 P2 R <<< $LN                   # get elements from line; use bashs "here string"
        [ "$P1" != "${P1/appMap}" ] && TGSCT=1          # test for the right target section ("appMap")

        OLDLVL=$LEVEL                                   # save nesting level
        T1=${LN//\{}                                    # compute actual nesting level (based on braces)
        T2=${LN//\}}
        LEVEL=$((LEVEL + ${#T2} - ${#T1}))              # which is count opening braces minus count closing braces

        [ "$TGSCT" -eq 0 ] &&   { echo "$LN"
                                  continue
                                }                       # not in right section: print and leave

        [ "$OLDLVL" -eq 2 ] &&  { URL=${P1//\"}         # test for nesting level (URL is 2), compute URL w/o double quotes
                                  TMP="$LN"             # save URL in variable and total line in temp. var
                                }

        [ "$P1" != "${P1/name}" ] && {  NM=${P2//\"}    # test for "name" tag, compute name value w/o double quotes
                                        LN="${TMP/$URL/${RP[$NM]}}"$'\n'"$LN"
                                                        # replace old URL with new URL
                                        URL=""; }       # empty URL variable

        [ -z "$URL" ] && echo "$LN"                     # print only if no URL has been intercepted

        [ "$LEVEL" -eq 0 ] && TGSCT=0                   # zero nesting level means target section left

   done < file                                          # read from json file

This is just straightforward functionality to prove it's working, there's nothing extra like error checking or debugging. If need be, this is left to the reader.