Ubuntu 16.04
bash -version
GNU bash, version 4.4.0(1)-release (x86_64-unknown-linux-gnu)

I would like to grep for 2 patterns and then have them listed side by side. ATM, this is what I have:

root@tires ~ # grep -e tire_id -e appID /path/to/*/vehicle/production.json
/path/to/000001_000002/vehicle/production.json:    "tire_id": "1305436516186552",
/path/to/000001_000002/vehicle/production.json:        "appID": "1164562920689523",
/path/to/000001_000079/vehicle/production.json:    "tire_id": "1815123428733289",
/path/to/000001_000079/vehicle/production.json:        "appID": "18412365908966538",
/path/to/000001_000088/vehicle/production.json:    "tire_id": "138477888324",

THis is what I would like to have or anything similar would work actually.

root@tires ~ # grep -e tire_id -e appID /path/to/*/vehicle/production.json
/path/to/000001_000002/vehicle/production.json:    tire_id: 1305436516186552, appID: 1164562920689523
/path/to/000001_000079/vehicle/production.json:    tire_id: 1815123428733289, appID: 18412365908966538

File example here:

{
    "socal": "https://xxx.xxxxx.xxx",
    "ip": "xxx.xxx.xxx.xxx",
    "tire_id": "213275925375485",
    "client": {
        "platform": "xx",
        "clientID": "xxxxx",
        "serviceID": "xxxxx",
        "service_id": XXXX,
        "vendor": "default"
    },
    "locale": "en_US",
    "cdc": {
        "appID": "233262274090443",
        "isdel": "ORdiZBMAQS2ZBCnTwZDZD",
    },
    "attachments": {
        "output": "attachments",
        "public": false,
    },
}
  • 4
    Looks like something more apt for jq than grep. – DopeGhoti Jul 12 at 15:25
  • 1
    post a testable production.json contents – RomanPerekhrest Jul 12 at 15:29
  • @RomanPerekhrest I posted an example, see OP. – needtoknow Jul 12 at 16:07
up vote 11 down vote accepted

The right way with jq tool for a valid JSON documents:

Sample file1.json:

{
    "socal": "https://xxx.xxxxx.xxx",
    "ip": "xxx.xxx.xxx.xxx",
    "tire_id": "213275925375485",
    "client": {
        "platform": "xx",
        "clientID": "xxxxx",
        "serviceID": "xxxxx",
        "service_id": "XXXX",
        "vendor": "default"
    },
    "locale": "en_US",
    "cdc": {
        "appID": "233262274090443",
        "isdel": "ORdiZBMAQS2ZBCnTwZDZD"
    },
    "attachments": {
        "output": "attachments",
        "public": false
    }
}

Sample file2.json:

{
    "socal": "https://xxx.xxxxx.xxx",
    "ip": "xxx.xxx.xxx.xxx",
    "tire_id": "1305436516186552",
    "client": {
        "platform": "xx",
        "clientID": "xxxxx",
        "serviceID": "xxxxx",
        "service_id": "XXXX",
        "vendor": "default"
    },
    "locale": "en_US",
    "cdc": {
        "appID": "1164562920689523",
        "isdel": "ORdiZBMAQS2ZBCnTwZDZD"
    },
    "attachments": {
        "output": "attachments",
        "public": false
    }
}

And the solution itself:

jq -r 'input_filename + " tire_id: \(.tire_id) appID: \(.cdc.appID)"' file*.json

The output:

file1.json tire_id: 213275925375485 appID: 233262274090443
file2.json tire_id: 1305436516186552 appID: 1164562920689523
  • Your answer is much simpler and efficient for what I needed. – needtoknow Jul 12 at 17:40

You can do this with grep but it's rather conplicated and Roman's answer is actually better.

Your example contents are just from one file so there is only once instance of tire_id and appID.

Use this:

echo $(echo /path/to/production.json && egrep "tire_id|appID" /path/to/production.json | sed -e 's|"||g' | sed -e 's|,||2') && echo $(echo /path/to/production2.json && egrep "tire_id|appID" /path/to/production2.json ) | sed -e 's|"||g' | sed -e 's|,||2'

echo puts everything on the same line with command substitution.

egrep does the same thing as grep -e but allows you to put all the strings together separated by | instead of having to use -e string each time.

sed -e 's|"||g' removes the apostrophes.

sed -e 's|,||2 removes the comma from the end of the value for appID which is what is shown in your desired output.

Output:

/path/to/production.json tire_id: 213275925375485 appID: 233262274090443
/path/to/production2.json tire_id: 1815123428733289 appID: 18412365908966538

/path/to/production.json and /path/to/production2.json are just placeholders.

This obviously requires a lot of modification as you'd have to grep each file separately and use an echo command substitution for each one. I'm only including it if you insist upon using grep or if in the future, it's not a json file.

  • @Your answer is awesome and I learned a lot from it. Much appreciated. You are also right about Roman's answer. He uses the command made for the job, which I did not know existed. Hat's off to you mate. – needtoknow Jul 12 at 17:40
  • 1
    @needtoknow No problem. Glad to help. – Nasir Riley Jul 12 at 17:48

With a sed script :

grep -e tire_id -e appID /path/to/*/vehicle/production.json | sed -n '/\(.*:\)/h;n;s/.*n://;H;g;s/\n//;p'

Retrun

/path/to/000001_000002/vehicle/production.json:    "tire_id": "1305436516186552",        "appID": "1164562920689523",
/path/to/000001_000079/vehicle/production.json:    "tire_id": "1815123428733289",        "appID": "18412365908966538",
/path/to/000001_000088/vehicle/production.json:    "tire_id": "138477888324",

it works if each line "tire_id" is followed by a line "appID". Otherwise, you need a more complex sed script

  • This is also nice. Can you remove the apostrophes and commas. – needtoknow Jul 12 at 20:01
  • sed -n 'h;n;s/.*n://;H;g;s/\n//;s/"//g;s/,//g;p' – alux Jul 12 at 21:09

This command will work even if in a file it misses a "tire_id" or "appID" line. It will not be displayed :

grep -e tire_id -e appID /path/to/*/vehicle/production.json | sed -n 's/\(tire_id\)/\1/;T;h;n;s/.*n:.*\(appID\)/\1/;T;H;g;s/\n/ /;s/"//g;s/,//g;p'
  • Very cool mate. I learned a lot from it. – needtoknow Jul 12 at 22:22

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.