Balok
Balok

Reputation: 143

JQ convert to number, convert to boolean when generating new json from shell variables

I'm attempting to generate json output where the input is coming from shell variables.

happystring="Bob Ross"
unhappynumber1="1942"
unhappyboolean=true

JSON=$(jq -n \
        --arg happystring "$happystring" --arg unhappynumber1 "$unhappynumber1" \
        --arg unhappyboolean $unhappyboolean \
        '
        {
            happystring: $happystring,
            unhappynumber1: $unhappynumber1,
            unhappyboolean: $unhappyboolean
        }
        ')

echo "$JSON" | jq

Produces this output:

{
  "happystring": "Bob Ross",
  "unhappynumber1": "1942",
  "unhappyboolean": "true"
}

I know I can use tonumber to convert a string to a number in a simple filter. However, I cannot figure out how to convert a string to a boolean. And I'm having trouble reasoning how to do either when sourcing from shell vars and creating new json as output.

Desired output:

{
  "happystring": "Bob Ross",
  "unhappynumber1": 1942,
  "unhappyboolean": true
}

Would it be easier or more clear if I produced the json and stored it in a shell var in one step, and then performed the additional conversion in a second step?

Upvotes: 12

Views: 10085

Answers (2)

lossleader
lossleader

Reputation: 13495

There's no need to convert variables to strings like --arg does only to convert them back, you can use --argjson and still input them separately but with types determined by the normal JSON rules:

happystring='"Bob Ross"'
unhappynumber1=1942
unhappyboolean=true

JSON=$(jq -n \
      --argjson happystring "$happystring" \
      --argjson unhappynumber1 "$unhappynumber1" \
      --argjson unhappyboolean "$unhappyboolean" \
      '
      {
          happystring: $happystring,
          unhappynumber1: $unhappynumber1,
          unhappyboolean: $unhappyboolean
      }
      ')

      echo "$JSON"

You could also mix --arg for strings and --argjson for everything else if you prefer not needing literal " quotes for the string arguments, as the note in the manual on shell quoting and the program text really applies to any arguments with characters you need to escape in your shell:

Note: it is important to mind the shell’s quoting rules. As a general rule it’s best to always quote (with single-quote characters) the jq program, as too many characters with special meaning to jq are also shell meta-characters. For example, jq "foo" will fail on most Unix shells because that will be the same as jq foo, which will generally fail because foo is not defined. When using the Windows command shell (cmd.exe) it’s best to use double quotes around your jq program when given on the command-line (instead of the -f program-file option), but then double-quotes in the jq program need backslash escaping.

Upvotes: 17

Kamal
Kamal

Reputation: 2554

You can use test filter to do the check and return true/false. And I think you can just use the filters directly, no need to create a json and convert again.

happystring="Bob Ross"
unhappynumber1="1942"
unhappyboolean=true

JSON=$(jq -n \
        --arg happystring "$happystring" --arg unhappynumber1 "$unhappynumber1" \
        --arg unhappyboolean $unhappyboolean \
        '
        {
            happystring: $happystring,
            unhappynumber1: $unhappynumber1 | tonumber,
            unhappyboolean: $unhappyboolean | test("true")
        }
        ')

echo "$JSON" | jq

will give output as:

{
  "happystring": "Bob Ross",
  "unhappynumber1": 1942,
  "unhappyboolean": true
}

Upvotes: 9

Related Questions