Using Multiple Layers of Quotes in Bash

Using multiple layers of quotes in bash

Normally, you could escape the inner quotes with \:

RANGE="-H \"Range: bytes=20-30\""

But this won't work when running a command – unless you put eval before the whole thing:

RANGE="-H \"Range: bytes=20-30\""
eval $CLIENT $REQ_HDRS $RSP_HDRS $RANGE

However, since you're using bash, not sh, you can put separate arguments in arrays:

RANGE=(-H "Range: bytes=20-30")
$CLIENT $REQ_HDRS $RSP_HDRS "${RANGE[@]}"

This can be extended to:

ARGS=(
-U # Request headers
-e # Response headers
-H "Range: bytes=20-30" # Range
)
$CLIENT "${ARGS[@]}"

bash dealing with multiple quotation

You can use here-doc to avoid quoting issues :

ssh node1 << 'EOF'
free -m | awk 'NR==2{printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'
EOF

Notice quotes around EOF so as to pass content as is.

We don't usually use -t of ssh if we just run commands directly

Escaping multiple layers of mixed quotes for a curl command executed inside a bash script

First, as I said in a comment, storing commands in variables just doesn't work right. Variables are for data, not executable code. Second, you have two levels of quoting here: quotes that're part of the shell syntax (which are parsed, applied, and removed by the shell before the arguments are passed to `curl), and quotes that're part of the JSON syntax.

But the second problem is actually worse than that, because simply embedding an arbitrary string into some JSON may result in JSON syntax errors if the string contains characters that're part of JSON syntax. Which passwords are likely to do. To get the password (and username for that matter) embedded correctly in your JSON, use a tool that understands JSON syntax, like jq:

userinfo=$(jq -n -c --arg u "$username" --arg p "$password" '{"username":$u,"password":$p}')

Explanation: this uses --arg to set the jq variables u and p to the shell variables $username and $password respectively (and the double-quotes around the shell variables will keep the shell from doing anything silly to the values), and creates a JSON snippet with them embedded. jq will automatically add appropriate quoting/escaping/whatever is needed.

Then, to use it with curl, use something like this:

resp=$(curl -k -i -H "Content-Type: application/json" -X POST -d "$userinfo" https://somerepo.example.com/flimflam)

Again, the double-quotes around $userinfo keep the shell from doing anything silly. You should almost always put double-quotes around variables references in the shell.

Note that I never used the req variable to store the command. If you need to print the command (or its equivalent), use something like this:

printf '%q ' curl -k -i -H "Content-Type: application/json" -X POST -d "$userinfo" https://somerepo.example.com/flimflam
echo

The %q format specifier tells the shell to add appropriate quoting/escaping so that you could run the result as a shell command, and it'd work properly. (And the echo is there because printf doesn't automatically add a newline at the end of its output.)

two layers of quotes around a bash variable

echo "loadings_file <- '$loadings' ; calls_file <- '$file'"

If you specifically need double quoting:

echo "loadings_file <- \"$loadings\" ; calls_file <- \"$file\""

Triple nested quotations in shell script

Here is an example. caller.sh uses gnome-terminal to execute foo.sh, which in turn prints all the arguments and then calls rsync with the first argument.

caller.sh:

#!/bin/bash
gnome-terminal -t "TEST" -e "./foo.sh 'long path' arg2 arg3"

foo.sh:

#!/bin/bash
echo $# arguments
for i; do # same as: for i in "$@"; do
echo "$i"
done
rsync "$1" "some other path"

Edit: If $1 contains several parameters to rsync, some of which are long paths, the above won't work, since bash either passes "$1" as one parameter, or $1 as multiple parameters, splitting it without regard to contained quotes.

There is (at least) one workaround, you can trick bash as follows:

caller2.sh:

#!/bin/bash
gnome-terminal -t "TEST" -e "./foo.sh '--option1 --option2 \"long path\"' arg2 arg3"

foo2.sh:

#!/bin/bash
rsync_command="rsync $1"
eval "$rsync_command"

This will do the equivalent of typing rsync --option1 --option2 "long path" on the command line.

WARNING: This hack introduces a security vulnerability, $1 can be crafted to execute multiple commands if the user has any influence whatsoever over the string content (e.g. '--option1 --option2 \"long path\"; echo YOU HAVE BEEN OWNED' will run rsync and then execute the echo command).

Bash Script single quotes inside of double quotes inside of single quotes

You don't need the bash -c layer; just run ssh itself directly from sudo.

sudo -H -u user1 ssh -I /home/user1/.ssh/id_rsa -f user2@machine1.domain1.com "find ./ -name \"*.txt\""

(The -I option should be unnecessary; if ssh is run as user1, then the default key is ~user1/.ssh/id_rsa. You may have meant -i anyway; -I specifies a PKCS#11 library to use, not a private key.)

That said, you cannot include single quotes inside a single-quoted string. When in doubt, use double quotes, and properly escape any nested double quotes.

How to escape single quotes within single quoted strings

If you really want to use single quotes in the outermost layer, remember that you can glue both kinds of quotation. Example:

 alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
# ^^^^^ ^^^^^ ^^^^^ ^^^^
# 12345 12345 12345 1234

Explanation of how '"'"' is interpreted as just ':

  1. ' End first quotation which uses single quotes.
  2. " Start second quotation, using double-quotes.
  3. ' Quoted character.
  4. " End second quotation, using double-quotes.
  5. ' Start third quotation, using single quotes.

If you do not place any whitespaces between (1) and (2), or between (4) and (5), the shell will interpret that string as a one long word.



Related Topics



Leave a reply



Submit