shell - Bash: Reading quoted/escaped arguments correctly from a string -
i'm encountering issue passing argument command in bash script.
poc.sh:
#!/bin/bash args='"hi there" test' ./swap ${args}
swap:
#!/bin/sh echo "${2}" "${1}"
the current output is:
there" "hi
changing poc.sh (as believe swap want correctly), how poc.sh pass "hi there" , test 2 arguments, "hi there" having no quotes around it?
a few introductory words
if @ possible, don't use shell-quoted strings input format.
- it's hard parse consistently: different shells have different extensions, , different non-shell implementations implement different subsets (see deltas between
shlex
,xargs
below). - it's hard programatically generate. ksh , bash have
printf '%q'
, generate shell-quoted string contents of arbitrary variable, no equilavent exists in posix sh standard. - it's easy parse badly. many folks consuming format use
eval
, has substantial security concerns.
nul-delimited streams far better practice, can accurately represent any possible shell array or argument list no ambiguity whatsoever.
xargs, bashisms
if you're getting argument list human-generated input source using shell quoting, might consider using xargs
parse it. consider:
array=( ) while ifs= read -r -d ''; array+=( "$reply" ) done < <(xargs printf '%s\0' <<<"$args") swap "${array[@]}"
...will put parsed content of $args
array array
. if wanted read file instead, substitute <filename
<<<"$args"
.
xargs, posix-compliant
if you're trying write code compliant posix sh, gets trickier. (i'm going assume file input here reduced complexity):
# not work entries containing literal newlines; need bash that. run_with_args() { while ifs= read -r entry; set -- "$@" "$entry" done "$@" } xargs printf '%s\n' <argfile | run_with_args ./swap
these approaches safer running xargs ./swap <argfile
inasmuch throw error if there more or longer arguments can accommodated, rather running excess arguments separate commands.
python shlex -- rather xargs -- bashisms
if need more accurate posix sh parsing xargs
implements, consider using python shlex
module instead:
shlex_split() { python -c ' import shlex, sys item in shlex.split(sys.stdin.read()): sys.stdout.write(item + "\0") ' } while ifs= read -r -d ''; array+=( "$reply" ) done < <(shlex_split <<<"$args")
Comments
Post a Comment