12

If I run:

cat <file> | jq 

I get:

{
  "user": "alex",
  "num": "486",
  "time": "Thu Jun  6 16:26:06 PDT 2019",
  "pwd": "/Users/alex/codes/ores/prompt-command",
  "pid": 11047,
  "exit_code": 0,
  "cmd": "echo '123'"
}
{
  "user": "john",
  "num": "487",
  "time": "Thu Jun  6 16:26:24 PDT 2019",
  "pwd": "/Users/alex/codes/ores/prompt-command",
  "pid": 11108,
  "exit_code": 5,
  "cmd": "echo '456'"
}
{
  "user": "alex",
  "num": "488",
  "time": "Thu Jun  6 16:26:59 PDT 2019",
  "pwd": "/Users/alex/codes/ores/prompt-command",
  "pid": 11141,
  "exit_code": 5,
  "cmd": "echo '789'"
}

but instead of all those fields, I just want some output like:

alex echo '123'
alex echo '789'

so I tried this:

cat <file> | jq -r '.user .cmd'

but that didn't work I got this error:

jq: error (at :63): Cannot index string with string "cmd"

I also want to filter it so I only see my commands, something like:

cat <file> | jq -r '.user=alex .cmd'
Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • Would just using `grep` here be sufficient? It wouldn't be quite as pretty but you would at least be able to get the two lines you care about – noah Jun 06 '19 at 23:54
  • 2
    BTW, it's generally much better form to pass the filename directly to the tool you're running (or to redirect with `<`). Not a huge difference for jq, but for tools like `sort` or `tail` that benefit from seekability, you can get a massive performance difference. (`cat hugefile | tail -n 1` will read `hugefile` beginning to end even though it only needs the last line; `tail -n 1 – Charles Duffy Jun 07 '19 at 00:14
  • @CharlesDuffy good point, thanks – Alexander Mills Jun 07 '19 at 00:22

2 Answers2

27

Use @tsv to generated tab-separated values as output:

jq -r '[.user, .cmd] | @tsv' <yourfile

...emits, given your input file:

alex    echo '123'
john    echo '456'
alex    echo '789'

...though if you're filtering for only your user account, you can just print cmd directly, since the user value is known:

jq -r 'select(.user == "alex") | .cmd' 
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
9

When you write .user .cmd you are asking for the "cmd" field of the JSON object at .user. To obtain both the .user and .cmd values, you could use the "," operator:

.user, .cmd

The above, however, will produce two lines. There are many options for emitting multiple values on a single line. You might wish to consider using string interpolation; or wrapping the values in square brackets and then using one of @csv, @tsv, or join/1; or using the -j command-line option.

This is all pretty clearly explained in the standard jq documentation (see e.g. https://stackoverflow.com/tags/jq/info), as is the use of select for making a selection.

peak
  • 105,803
  • 17
  • 152
  • 177