5

i need to print key and values from a json string. i allready parse a simple json string

            {
              "Name": "test1",
              "CreateDate": "2016-08-30T10:52:52Z",
              "Id": "testId1",
            }

my code like this

 q1=$(echo $x | grep -Po '"Name":.*?[^\\]",'| perl -pe 's/"Name": //; s/^"//; s/",$//');

 q2=$(echo $x | grep -Po '"Id":.*?[^\\]",'| perl -pe 's/"Id": //; s/^"//; s/",$//');

    echo $q1 "," $q2;

But this code is not applicable for json string like this

x='{    "TestNames":
        [{
        "Name": "test1",
        "CreateDate": "2016-08-30T10:52:52Z",
        "Id": "testId1"
         }, 
         {
        "Name":  "test2",
        "CreateDate": "2016-08-30T10:52:13Z",
        "Id": "testId2"
    }]
}';

I need to print like this

test1 , testId1
test2 , testId2

is it possible to get data like this using grep command?

Abdul Manaf
  • 4,933
  • 8
  • 51
  • 95
  • the data is not valid json. A json parser would say: `parse error: Expected another key-value pair at line 6, column 10` (The command after a key-value pair is only allowed if it is followed by another key/value pair) – hek2mgl Aug 30 '16 at 12:21
  • Since everyone suggests you to install 3rd party programs.. If your JSON Format does not change and your key's are limited and you need a *pure Bash+grep* solution you could [grep the Names and Ids in 2 bash Arrays separately](http://stackoverflow.com/a/24890830/3828957) and then [print them side by side](http://stackoverflow.com/a/16510716/3828957). – makadev Aug 30 '16 at 12:30
  • @makadev *If your "JSON" Format does not change and your key's are limited and you need a pure Bash+grep solution* ... you are doing something wrong. – hek2mgl Aug 30 '16 at 12:31
  • @hek2mgl why, because of giving another solution? You do notice that your "duplicates" accepted answer suggest installation of a js/json parser, so do many other.. this may not be an option in certain environments. If it was a good solution, I wouldn't write it in comments. Besides, no one noticed the usage of perl.. why not use perls JSON module... – makadev Aug 30 '16 at 12:36
  • If your application requires to process json and you have nothing that can parse json on your servers plus you can't install something then you are doing it wrong. – hek2mgl Aug 30 '16 at 12:38
  • @makadev, a `grep` solution can't handle `\n` sequences in a JSON string, or `\t`s, or `\"`s -- and ensuring that your code will break the moment the content changes is making your solution as a whole needlessly brittle. I've had customers build code so fragile it couldn't even handle a different key order in a dictionary in JSON -- which, as soon as we upgraded our serialization library (much less extended the API), meant those customers had screwed themselves. Leading people down that path is utterly unwise. – Charles Duffy Aug 30 '16 at 15:01
  • @CharlesDuffy Noted, Escapes and Unicode Sequences are a problem. To be pedantic - it's still a (low quality) solution for the question since there is no further information about usage of the output and wether it is scratch work or just interest/feasibility check. Personally - as strict FHS and stable tree linux user - I would not accept an "Install xyz" answer without a good reasoning (which is missing). As developer I'm often restricted to a set of "applications" I'm allowed to use, often due to requirements and not because "you are doing it wrong". Anyway, thats all from my side. – makadev Aug 30 '16 at 16:18
  • @makadev, if "install X" isn't an option, the usual answer is to have a shell function that calls a snippet of Python (which has included a json module in its standard library since what are now ancient times). There are still better options that grep and company. – Charles Duffy Aug 30 '16 at 16:21

2 Answers2

11

First, your data is not valid json, there is a comma too much:

{
  "TestNames": [
    {
      "Name": "test1",
      "CreateDate": "2016-08-30T10:52:52Z",
      "Id": "testId1", <--- Remove that!
    },
    {
      "Name": "test2",
      "CreateDate": "2016-08-30T10:52:13Z",
      "Id": "testId2"
    }
  ]
}

Once you've fixed that you can use jq for parsing json on the command line:

echo "$x" | jq -r '.TestNames[]|"\(.Name) , \(.Id)"'

if you need to keep the output values.

declare -A map1

while read name id ; do
    echo "$name"
    echo "$id"
    map1[$name]=$id

done < <(echo "$x" | jq -r '.TestNames[]|"\(.Name) \(.Id)"')

echo "count : ${#map1[@]}"
echo "in loop: ${map1[$name]}"
Abdul Manaf
  • 4,933
  • 8
  • 51
  • 95
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • is it possible to add result to variables separatly, using this method? (eg : print1= echo "$x" | jq -r '.TestNames[]|"\(.Name) , \(.Id)"'; echo $print1; – Abdul Manaf Aug 30 '16 at 13:01
  • Are you searching for [*command substitution*](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html)? – hek2mgl Aug 30 '16 at 13:02
  • i need to create a hash table(key:name,value=Id) using json parse output. because i need Name and Id separately. is it possible with this solution? – Abdul Manaf Aug 30 '16 at 13:09
  • I would use a while loop, like this: http://pastebin.com/SEh22pAH – hek2mgl Aug 30 '16 at 13:14
  • 1
    thanks hek2mgl, its working for me. i look solution like this – Abdul Manaf Aug 30 '16 at 13:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/122204/discussion-between-abdul-manaf-and-hek2mgl). – Abdul Manaf Aug 30 '16 at 13:37
  • why `jq -r '.TestNames[]|"\(.Name) \(.Id)"'` works but not `jq -r ".TestNames[]|'\(.Name) \(.Id)'"` – wsdzbm Feb 11 '23 at 22:41
  • @wsdzbm Strings in jq have to be enclosed in double quotes. Similar to json – hek2mgl Feb 25 '23 at 20:21
2

I'd recommend using jq, a command-line JSON parser :

$ echo '''{
          "Name": "test1",
          "CreateDate": "2016-08-30T10:52:52Z",
          "Id": "testId1"
        }''' | jq  '.Name + " , " + .Id'

"test1 , testId1"


$ echo '''{    "TestNames":
    [{
    "Name": "test1",
    "CreateDate": "2016-08-30T10:52:52Z",
    "Id": "testId1"
     },
     {
    "Name":  "test2",
    "CreateDate": "2016-08-30T10:52:13Z",
    "Id": "testId2"
}]
}''' | jq '.TestNames[] | .Name + " , " + .Id'

"test1 , testId1"
"test2 , testId2"
Aaron
  • 24,009
  • 2
  • 33
  • 57