Wednesday, 27 January 2021

JQ - Syntax on macOS vs. Linux

 I keep forgetting that the syntax of commands on macOS often varies from Linux platforms, such as Ubuntu.

JQ ( jq ) is a good example.

So here's an example using json_pp ( JSON Print Pretty )

echo '{"givenName":"Dave","familyName":"Hay"}' | json_pp

{
   "givenName" : "Dave",
   "familyName" : "Hay"
}

and here's the same example using jq 

echo '{"givenName":"Dave","familyName":"Hay"}' | jq

{
  "givenName": "Dave",
  "familyName": "Hay"
}

both on macOS.

Having spun up an Ubuntu container: -

docker run -it ubuntu:latest bash

and installed json_pp and jq: -

apt-get update && apt-get install -y libjson-pp-perl

and: -

apt-get update && apt-get install -y jq

here's the same pair of examples: -

echo '{"givenName":"Dave","familyName":"Hay"}' | json_pp

{
   "familyName" : "Hay",
   "givenName" : "Dave"
}

echo '{"givenName":"Dave","familyName":"Hay"}' | jq


{
  "givenName": "Dave",
  "familyName": "Hay"
}

So far, so good.

To be sure, on both macOS and Ubuntu, I double-checked the version of jq : -

jq --version

jq-1.6

Again, all is fine.

And then I hit an issue ....

I was building a Jenkins Job that runs from a GitHub repo, with a Jenkinsfile that invokes a Bash script.

At one point, I saw: -

jq - commandline JSON processor [version 1.5-1-a5b5cbe]
Usage: jq [options] <jq filter> [file...]
jq is a tool for processing JSON inputs, applying the
given filter to its JSON text inputs and producing the
filter's results as JSON on standard output.
The simplest filter is ., which is the identity filter,
copying jq's input to its output unmodified (except for
formatting).
For more advanced filters see the jq(1) manpage ("man jq")
and/or https://stedolan.github.io/jq
Some of the options include:
-c compact instead of pretty-printed output;
-n use `null` as the single input value;
-e set the exit status code based on the output;
-s read (slurp) all inputs into an array; apply filter to it;
-r output raw strings, not JSON texts;
-R read raw strings, not JSON texts;
-C colorize JSON;
-M monochrome (don't colorize JSON);
-S sort keys of objects on output;
--tab use tabs for indentation;
--arg a v set variable $a to value <v>;
--argjson a v set variable $a to JSON value <v>;
--slurpfile a f set variable $a to an array of JSON texts read from <f>;
See the manpage for more options.

Note the version of jq being reported - by default, it is: -

1.5-1-a5b5cbe

To validate this, I created a basic Jenkinsfile: -

timestamps {
    node('cf_slave') {
      stage('Testing jq') {
        sh '''#!/bin/bash
              which jq
              ls -al `which jq`
              jq --version
              echo '{"givenName":"Dave","familyName":"Hay"}' | jq
            '''
            }
    }
}

which: -

(a) show which jq is being used

(b) shows the file-path of that jq

(c) shows the version of that jq

(d) attempts to render the same bit of JSON

which returned: -

09:06:22  /usr/bin/jq
09:06:22  -rwxr-xr-x 1 root root 280720 Sep  7  2018 /usr/bin/jq
09:06:22  jq-1.5-1-a5b5cbe
09:06:22  jq - commandline JSON processor [version 1.5-1-a5b5cbe]
09:06:22  Usage: jq [options] <jq filter> [file...]
09:06:22  
09:06:22   jq is a tool for processing JSON inputs, applying the
09:06:22   given filter to its JSON text inputs and producing the
09:06:22   filter's results as JSON on standard output.
09:06:22   The simplest filter is ., which is the identity filter,
09:06:22   copying jq's input to its output unmodified (except for
09:06:22   formatting).
09:06:22   For more advanced filters see the jq(1) manpage ("man jq")
09:06:22   and/or https://stedolan.github.io/jq
09:06:22  
09:06:22   Some of the options include:
09:06:22   -c compact instead of pretty-printed output;
09:06:22   -n use `null` as the single input value;
09:06:22   -e set the exit status code based on the output;
09:06:22   -s read (slurp) all inputs into an array; apply filter to it;
09:06:22   -r output raw strings, not JSON texts;
09:06:22   -R read raw strings, not JSON texts;
09:06:22   -C colorize JSON;
09:06:22   -M monochrome (don't colorize JSON);
09:06:22   -S sort keys of objects on output;
09:06:22   --tab use tabs for indentation;
09:06:22   --arg a v set variable $a to value <v>;
09:06:22   --argjson a v set variable $a to JSON value <v>;
09:06:22   --slurpfile a f set variable $a to an array of JSON texts read from <f>;
09:06:22   See the manpage for more options.

So, there's the issue - the default version of jq that's included within my cf_slave container is out-of-date.

There are two resolutions here: -

(a) Install an up-to-date version of jq

(b) Add a trailing period to the jq command

echo '{"givenName":"Dave","familyName":"Hay"}' | jq .

{
  "givenName": "Dave",
  "familyName": "Hay"
}

I'm still working on the former: -

sudo apt-get update && sudo apt-get install -y jq

which results in: -

09:24:14  jq is already the newest version (1.5+dfsg-1ubuntu0.1).

so I need to dig into my cf_slave container a bit more ...

In the meantime, the latter resolution ( adding the trailing period ) does the trick: -

09:24:14  /usr/bin/jq
09:24:14  -rwxr-xr-x 1 root root 280720 Sep  7  2018 /usr/bin/jq
09:24:14  jq-1.5-1-a5b5cbe
09:24:14  {
09:24:14    "givenName": "Dave",
09:24:14    "familyName": "Hay"
09:24:14  }

No comments:

Note to self - use kubectl to query images in a pod or deployment

In both cases, we use JSON ... For a deployment, we can do this: - kubectl get deployment foobar --namespace snafu --output jsonpath="{...