I have the following code:
set -o xtrace
openDirectory ()
{
lxterminal --command="zsh -c 'cd "$1"; zsh -i' "
}
# Handle argument.
if [ "$@" ]
then
openDirectory ~/Projects/Clients/"@1"
cd $1
fi
This fails if there is a space in the argument passed.
lxterminal '--command=zsh -c '\''cd /home/chris/Projects/Clients/Test' - 'Space; zsh -i'\'' '
cd Test - Space
cd: too many arguments
How can I properly escape this? Is this even feasible to be done with something like bash?
Assuming the enclosing shell really is bash (as the question is tagged), you can use printf -v varname %q "$var"
to store a safely quoted instance of the value of var
into the variable named varname
, as such:
openDirectory()
{
local cd_cmd cmd
printf -v cd_cmd '%q ' cd "$1"
printf -v cmd '%q ' zsh -c "$cd_cmd && zsh -i"
lxterminal --command="$cmd"
}
printf '%q'
evaluates to a version of the given string which will, when eval
'ed by bash (or any shell with equivalent semantics), evaluate to the original literal value.
To explain why this is done that way:
- In the above, all quote characters included in the code itself are syntactic rather than literal: We're depending on
printf %q
for all quoting and escaping. This is a best-practice approach: Using literal quotes means that literals inside the data being generated are able to escape those quotes.
- Running shell directives such as
&&
through shell quoting will make them into literal data. Thus, we want the &&
to be literal data rather than syntax when we're passing it as an argument to -c
, but not literal data when handled by the remote shell -- this is why it's only present in the last quoting pass.
Even though a good suggestion was made in the comments, as a general way to deal with such issues you could write it this way :
set -o xtrace
openDirectory ()
{
local safe_path
printf -v safe_path "%q" "$1"
lxterminal --command="zsh -c 'cd $safe_path; zsh -i' "
}
For a better way to prepare the command to be passed as argument to lxterminal
, please see CharlesDuffy's answer.
As for the rest of your code, I would probably use the following :
# Handle argument.
if
[ -d "$1" ]
then
openDirectory ~/Projects/Clients/"@1"
cd "$1"
fi
Using "$@"
as the if condition could yield 0 (true) and execute the body if argument 1 exists but is empty (null string), but a following argument is not. I I assume this is not what you want.
I am unsure if "@1" is a typo or if it really is intended to mean a directory named "@1" inside your "Projects/Clients" directory. But the "$1"
argument to cd
should be quoted, for sure.