A situation that I've run into a few times: I have a shell function that does some setup and then invokes a more-or-less arbitrary command, like this:
setup_and_run() {
some_setup_commands
"$@"
}
I want to alter this function to also write a script file that I can use to re-run the command after doing the same setup. I can do the following, which works when there are no arguments with spaces or other weird stuff in the command:
setup_and_run() {
some_setup_commands
cat >>rerun.sh <<EOF
some_setup_commands
$@
EOF
"$@"
}
Is there a standard way to alter this so that the script gets written with proper quoting, in general, even if some arguments have spaces or other special characters?
For example, with the second definition of setup_and_run
, if I run
$ setup_and_run ls "my cat's \"password\""
my cat's "password"
then rerun.sh
will contain
some_setup_commands
ls my cat's "password"
whereas I want it to contain something like
some_setup_commands
ls "my cat's \"password\""
or
some_setup_commands
ls my\ cat\'s\ \"password\"
or some such thing.
In a pinch I can outsource this to something like Python's shlex.quote()
, but I'm looking for something that can be done in the shell itself if possible, or at least using a lighter-weight standard UNIX tool.
Best Answer
In bash, ksh93 and zsh, you can use the
%q
escape for theprintf
builtin.In bash, you can use the
printf -v
to write the output to a variable rather than to standard output.In zsh, there's a different method which is the
q
parameter expansion flag, followed byj: :
to join the array elements with a space.In plain sh, it's more difficult. A reliable way to quote a word is to put single quotes around it, and replace each single quote inside by
'\''
. Making the replacement correctly is not very easy, involving either an external call to sed or a loop.