Vivek Goel
Vivek Goel

Reputation: 24160

Properly escaping Json command line option in bash script

I have utility which accept JSON as argument. How to escape json correctly to pass to the utility? Example:

ip="127.0.0.1"
action='{\"server_ip\":\"$ip\",\"action\":\"stop\"}'
./fix-utility -e $action

But JSON is not getting escaped correctly.

Upvotes: 6

Views: 21068

Answers (3)

Thomas BDX
Thomas BDX

Reputation: 2800

Updating this old question with newer tools. This solution relies on python's jq since it's a great tool for manipulating JSON files and strings.

Using the native bash string concatenation, one can do without having to escape anything manually and rely on jq to perform all the escaping.

# let's say I have need to include a variable within a string containing characters to escape
> my_string='a'"b"'c'
> echo -e "$my_string"
abc

> my_string='!(){'"$variable"'}[]'
> echo -e "$my_string"
!(){my_value_here}[]

# in effect, I'm concatenating these 3 strings together:
'!(){'
"$variable"
'}[]'

The single quotes prevent interpretation by bash, the double quote allow interpretation of the variable by bash.

Now, to escape, I would advise using python's jq program (pip install jq).

> ip="127.0.0.1"
> action='{"action":"stop","server_ip":"'"$ip"'"}'
> echo -e "${action}" | jq -cM '. | @text '
"'{\"action\":\"stop\",\"server_ip\":\"127.0.0.1\"}'"

For context, here are the versions of bash and jq that I'm using:

> bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.
> jq --version
jq-1.6

Upvotes: 1

F. Hauri  - Give Up GitHub
F. Hauri - Give Up GitHub

Reputation: 70872

Double quotes and single quotes is not considered same by bash interpreter: While double-quote let bash expand contained variables, single quote don't. Try simply:

echo "$BASH_VERSION"
4.1.5(1)-release
echo '$BASH_VERSION'
$BASH_VERSION

At all, there is a nice reusable bash way:

declare -A jsonVar
toJsonString() {
    local string='{'
    for var in ${!jsonVar[*]} ;do
        string+="\"$var\":\"${jsonVar[$var]}\","
      done
    echo ${string%,}"}"
}

jsonVar[action]=stop
jsonVar[server_ip]=127.0.1.2

toJsonString
{"action":"stop","server_ip":"127.0.1.2"}

And finally:

./fix-utility -e "$(toJsonString)"

This could be improved if specials chars like " double-quotes have to be part of some strings.

Upvotes: 2

tripleee
tripleee

Reputation: 189648

If you want interpolation of e.g. $ip inside the string, you need to use double quotes. Double quotes in the value need backslash escaping.

ip="127.0.0.1"
action="{\"server_ip\":\"$ip\",\"action\":\"stop\"}"
./fix-utility -e "$action"

Actually, I would advise against storing the action in a variable, unless your example omits something crucial which makes it necessary.

Upvotes: 7

Related Questions