Bash:从string中正确读取引用/转义的参数
我遇到了一个问题,在Bash脚本中传递参数给一个命令。
poc.sh:
#!/bin/bash ARGS='"hi there" test' ./swap ${ARGS}
交换:
#!/bin/sh echo "${2}" "${1}"
目前的产出是:
there" "hi
只改变poc.sh(因为我相信交换做我想要它正确),我怎么得到poc.sh通过“喂那里”和testing作为两个参数,与“你好”没有引号周围呢?
几个引导词
如果可能的话, 不要使用shell引用的string作为input格式。
- 很难一致地parsing:不同的shell有不同的扩展,不同的非shell实现实现不同的子集(参见下面的
shlex
和xargs
之间的delta)。 - 编程生成很难。 ksh和bash都有
printf '%q'
,它会生成一个带有任意variables内容的shell引用的string,但是在POSIX sh标准中没有这样的等号。 - 这很容易parsing。 许多使用这种格式的人使用
eval
,这有很大的安全性问题。
NUL分隔的stream是一个好得多的做法,因为它们可以精确地表示任何可能的shell数组或参数列表,而没有任何含糊之处。
xargs,与bashisms
如果您使用shell引用从人为生成的input源获取参数列表,则可以考虑使用xargs
来parsing它。 考虑:
array=( ) while IFS= read -r -d ''; do array+=( "$REPLY" ) done < <(xargs printf '%s\0' <<<"$ARGS") swap "${array[@]}"
…将parsing的$ARGS
内容放入数组array
。 如果您想从文件中读取,请将<filename
<<<"$ARGS"
replace为<<<"$ARGS"
<filename
<<<"$ARGS"
。
xargs,POSIX兼容
如果你试图编写符合POSIX sh的代码,这会变得棘手。 (为了降低复杂性,我将在这里假设文件input):
# This does not work with entries containing literal newlines; you need bash for that. run_with_args() { while IFS= read -r entry; do set -- "$@" "$entry" done "$@" } xargs printf '%s\n' <argfile | run_with_args ./swap
这些方法比运行xargs ./swap <argfile
更安全,因为如果有更多或更多的参数,它会抛出一个错误,而不是作为单独的命令运行多余的参数。
Python shlex – 而不是xargs – 与bashisms
如果您需要比xargs
实现更精确的POSIX shparsing,请考虑使用Python shlex
模块:
shlex_split() { python -c ' import shlex, sys for item in shlex.split(sys.stdin.read()): sys.stdout.write(item + "\0") ' } while IFS= read -r -d ''; do array+=( "$REPLY" ) done < <(shlex_split <<<"$ARGS")
embedded的引号不保护空白; 他们从字面上看待。 在bash
使用一个数组:
args=( "hi there" test) ./swap "${args[@]}"
在POSIX shell中,你使用eval
卡住(这就是为什么大多数shell支持数组)。
args='"hi there" test' eval "./swap $args"
像往常一样,要非常确定地知道$args
的内容,并理解在使用eval
之前如何parsing结果string。
这可能不是最稳健的方法,但它很简单,似乎适用于您的情况:
## demonstration matching the question $ ( ARGS='"hi there" test' ; ./swap ${ARGS} ) there" "hi ## simple solution, using 'xargs' $ ( ARGS='"hi there" test' ; echo ${ARGS} |xargs ./swap ) test hi there