Escaping Bash Variable

how to escape file path in bash script variable

With GNU bash and its Parameter Expansion:

echo "${CONFIG//\//\\/}"

Output:


\/home\/teams\/blabla\/blabla.yaml

Do not escape within a bash variable

Storing Bash code in variables is a recipe for (un)escaping bugs. Not to mention how dramatically the script’s behavior can change due to (untrusted) values of expanded variables, especially when combined with eval.

If you want to store a piece of Bash code for later (re)use, use a function:

executor() {
env UNROLL="${u}" TB="${tb}" "${APP_DIR}/${tp}" "${idx}" > output.txt
}

executor

A more flexible option would be to get the expanded variables and the target file name from the executor function’s arguments, to make it more self-contained and less context-dependent.

executor() {
local -n args="$1"
env UNROLL="${args['UNROLL']}" \
TB="${args['tb']}" \
"${args['APP_DIR']}/${args['tp']}" "${args['idx']}" > "${args['output']}"
}

declare -A some_executor_arguments=(
['UNROLL']='blah_unroll'
['tb']='blah_tb'
['APP_DIR']='/some/dir/blah'
['tp']='some_app'
['idx']='5'
['output']='output.txt'
)

executor some_executor_arguments

Escaping special characters in bash variables

Part of the problem here is that the local and remote filenames are parsed differently: the local filename is used directly, so the only thing you need to do is enclose it in double-quotes (as in @Ignacio's answer), but the remote filename gets passed to a remote shell which runs it through another layer of parsing (quote and escape removal, etc). So, you want to add escapes to the remote path only. I've also taken the liberty of simplifying the sed command a little:

#!/bin/sh

promote_to=random.server.com
dev_catalog=/folderX/
uat_catalog=/folderY/

while read line
do
uat_path="$(echo "$uat_catalog$line" | sed -e 's/[()&]/\\&/g')"
dev_path="$dev_catalog$line"

scp "$dev_path" "user@$promote_to:$uat_path"
scp "$dev_path.atr" "user@$promote_to:$uat_path.atr"
done < "input.txt"

Note that the sed pattern I used, 's/[()&]/\\&/g', only escapes parentheses and ampersands; if your filenames contain any other shell metacharacters, be sure to add them to the character list in [].

How to escape characters in a shell script variable

This produces what you wish to see.

read message
ping "${message}"

Should I escape variables in bash script or not

All quotes passed on the command line are handled by the shell (in this case bash). After all variables got expanded the resulting strings are passed as arguments to the executed program, where arguments are delimited by (unquoted) space on the command line.

Therefore in your examples

cqlsh "${CASSANDRA_IP}" -u "${CASSANDRA_USER}" -p "${CASSANDRA_PASSWORD}" -f command.cql

is equivalent to

cqlsh 00.000.00.00 -u user -p 'password' -f command.cql

which is equivalent to

cqlsh 00.000.00.00 -u user -p password -f command.cql

i.e. the shell will call the program cqlsh passing it 7 arguments

  1. 00.000.00.00
  2. -u
  3. user
  4. -p
  5. password
  6. -f
  7. command.cql

Quoting correctly is very important nevertheless because of how shells handle variable expansion, most importantly by this rules (this is for bash but should be applicable for most other shells too):

  • strings in single quotes ' are not subject to any variable expansion and get passed literally
  • strings in double quotes " are subject to variable expansion: the final result of the expansion will be passed as one string to the program
  • unquoted variables will be expanded on the command line and the resulting command line then gets executed

Most of the time the end result of enclosing variables in double quotes and passing them unquoted is the same, but it may be different depending on the value of the variable, especially when containing space characters: in this case the result will be passed as multiple strings to the program instead of a single string. E.g.

CASSANDRA_PASSWORD="my password" # password contains a space

cqlsh $CASSANDRA_IP -u $CASSANDRA_USER -p $CASSANDRA_PASSWORD -f command.cql

would be evaluated to

cqlsh 00.000.00.00 -u user -p my password -f command.cql

i.e. cqlsh would be called with 8 arguments instead of the intended 7:

  1. 00.000.00.00
  2. -u
  3. user
  4. -p
  5. my
  6. password
  7. -f
  8. command.cql

whereas

cqlsh "$CASSANDRA_IP" -u "$CASSANDRA_USER" -p "$CASSANDRA_PASSWORD" -f command.cql

would correctly evaluate to

cqlsh 00.000.00.00 -u user -p "my password" -f command.cql


Related Topics



Leave a reply



Submit