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
00.000.00.00
-u
user
-p
password
-f
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:
00.000.00.00
-u
user
-p
my
password
-f
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
Bash Script for Executing Commands on Multiple Server
Case Statement in a While Loop, Shell Scripting
How to Build Kernel Debug Info as Separate File
How to Continue Next Iteration When an Error Occurs in Bash
Command Execution with Nohup in Background
Why Does Cat <<< $Var1 Lose Newlines
How to Configure/Make/Install Against an Older Version of a Library
How to Find Libstdc++.So.6: That Contain Glibcxx_3.4.19 for Rhel 6
Behavior of Writing to Tcp Socket Before Reading All Data
The Behavior When a Gnu Make Phony Target Happens to Be The Same as a Directory Name
Command and Script to Re-Read a File in Gnuplot
Linking with 32Bit Libraries Under Linux 64Bit
Implementation of Syscall() on Arm-Oabi. What Is "Svc #0X900071"
Get Apache Total CPU Usage in (Linux)
Difference Between The Commands "Gcloud Compute Ssh" and "Ssh"