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,xargsbelow). - 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