Bash Argument Parsing and Quoting |
October 4th, 2016 |
| bash, tech |
bash is an awkward language, and
handling of arguments is certainly one of them. Here are two things
you might like to do in a shell:
- quoting: turn an array into a string, using shell-style escaping
- unquoting: turn a string into an array, interpreting shell-style escaping
argument1 argument two argument three argument='four and'There are multiple ways you could quote these as arguments, so here's one example:
argument1 "argument two" "argument three" "argument='four and'"Basically, I want Python's shlex, with its
quote and split, but I want it in bash.
Unfortunately, bash can't do this easily. What can you do?
Quoting you have to do yourself, but it's pretty straight-forward.
Replace \ with \\, ' with \', and
wrap each argument in 's if it contains anything suspicious.
Here's something that does this:
function quote() {
first=true
for arg in "$@"; do
if $first; then first=false; else echo -n " "; fi
if echo "$arg" | grep -q '[^a-zA-Z0-9./_=-]'; then
arg="'$(echo "$arg" | sed -e 's~\\~\\\\~g' -e "s~'~\\\\'~g")'"
fi
echo -n "$arg"
done
echo
}
Going the other way is both simpler and kind of evil. It turns out that the way you do this is:
eval unquoted=("$quoted")
A warning though: if quoted contains things like $(echo
foo) then they will be run. In many cases this isn't a problem,
but it's something to be aware of.
(I needed both of these when writing the automated installation script
for ngx_pagespeed. You need to be able to give it arguments to pass
through to nginx's ./configure, and I wanted people to be
able to enter them exactly as they would on the command line. This
means I need to parse them into an array first. On the other hand, if
you're just using the script to set up ngx_pagespeed it needs to print
out a string that you should paste as ./configure arguments,
which means I need quoting as well.)
[1] Which would actually need to work like read and be passed
the name of a variable to put the array in, since you can't return
arrays in bash.
Comment via: google plus, facebook, hacker news, substack