Bash 从字符串中正确读取引用/转义参数
我在Bash脚本中将参数传递给命令时遇到了一个问题 poc.sh:Bash 从字符串中正确读取引用/转义参数,bash,shell,sh,Bash,Shell,Sh,我在Bash脚本中将参数传递给命令时遇到了一个问题 poc.sh: #!/bin/bash ARGS='"hi there" test' ./swap ${ARGS} 互换: 电流输出为: there" "hi 仅更改poc.sh(因为我相信swap能正确地实现我所希望的),如何让poc.sh通过“hi-there”并作为两个参数进行测试,而“hi-there”周围没有引号?嵌入引号不保护空白;他们被逐字逐句地对待。在bash中使用数组: args=( "hi there" test) .
#!/bin/bash
ARGS='"hi there" test'
./swap ${ARGS}
互换:
电流输出为:
there" "hi
仅更改poc.sh(因为我相信swap能正确地实现我所希望的),如何让poc.sh通过“hi-there”并作为两个参数进行测试,而“hi-there”周围没有引号?嵌入引号不保护空白;他们被逐字逐句地对待。在
bash
中使用数组:
args=( "hi there" test)
./swap "${args[@]}"
在POSIX shell中,您无法使用eval
(这就是大多数shell支持数组的原因)
像往常一样,在使用eval
一些介绍性词语之前,请确保您知道$args
的内容,并了解如何解析生成的字符串
如果可能的话,不要使用带shell引号的字符串作为输入格式
- 解析一致性很难:不同的shell具有不同的扩展,不同的非shell实现实现不同的子集(请参见下面的
和shlex
之间的增量)xargs
- 很难通过编程方式生成。ksh和bash有
,它将生成一个包含任意变量内容的shell引用字符串,但在POSIX sh标准中不存在与此等效的字符串printf“%q”
- 它很容易解析。许多使用这种格式的人使用
,这有很大的安全隐患eval
沙尔格,带着巴西主义
如果你使用shell引用从一个人类生成的输入源获取你的参数列表,你可以考虑使用<代码> XARGS来解析它。考虑:
array=( )
while IFS= read -r -d ''; do
array+=( "$REPLY" )
done < <(xargs printf '%s\0' <<<"$ARGS")
swap "${array[@]}"
这些方法比运行
xargs./swap更安全这可能不是最可靠的方法,但它很简单,似乎适合您的情况:
## 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
丑陋的想法警报:纯Bash函数
这是一个用纯bash编写的带引号的字符串解析器(多么可怕的乐趣)
警告:就像上面的xargs示例一样,这在转义引号的情况下是错误的。这是可以解决的。。。但在实际的编程语言中要做得更好
示例用法
MY_ARGS=“foo'bar baz'qux*”'$(危险)“sudo ls-lah”
#从多行字符串创建数组
IFS=$'\r\n'GLOBIGNORE='*'args=($(parseargs“$MY_args”))
#显示数组中的每个参数
对于“${args[@]}”中的arg;做
回显“$arg”
完成
示例输出
解析参数函数
这实际上是一个字符接一个字符,并添加到当前字符串或当前数组中
set-u
set-e
#ParseArgs将像bash一样解析包含带引号字符串的字符串
#(与大多数其他*nix shell相同)。这是安全的,因为它不做任何事情
#执行或解释。然而,它也不能逃逸,所以你不应该通过
#这些字符串在不转义的情况下连接到壳。
parseargs(){
notquote=“-”
str=$1
声明-a args=()
s=“”
#先去掉前导空格,然后去掉尾随空格,最后用空格结束。
str=“${str}”
str=“${str%%}”
str+=“”
last_quote=“${notquote}”
is_space=“”
n=$(${str}-1))
对于((i=0;这是BashFAQ 50的主题:我倾向于认为这里有更多的选项eval
。即使在POSIX中,也可以从xargs读入“$@”
。这似乎不适用于ARGS=“\”a\\\\\“b\”c“
?错误报告的xargs:不匹配的双引号;默认情况下,除非您使用-0 optionFair point--xargs
在这种情况下确实不遵守POSIX sh行为。使用Python 2的shlex.split()使用替代方法更新
功能。最好将OP放回正确的轨道:如果OP需要这样的功能,那么他们的设计显然是错误的。除非OP正在编写shell(或cli),在这种情况下,语言的选择是错误的。无论哪种情况,OP都做得不对。@gniourf_gniourf,……理论上,我同意。在实践中,人们往往被给予毫无意义的要求(或者需要与长期存在的系统/实践兼容——有大量传统的Java应用程序启动脚本依赖于以shell引用形式给出的eval
ing参数列表),能够充分利用坏情况是有价值的……当然,“不要这样做”应该是给出的建议的一部分。@gniourf_gniourf,…我编辑了一篇适当的介绍。评论:Bash字符串处理非常混乱。xargs
通过直接传递参数来消除猜测,这绕过了Bash作为字符串一部分执行的正常、反复无常的字符串处理-基于命令行处理。我不能确定我关于exec
的断言。但我坚持我的说法,“Bash字符串处理非常混乱”。
array=( )
while IFS= read -r -d ''; do
array+=( "$REPLY" )
done < <(xargs printf '%s\0' <<<"$ARGS")
swap "${array[@]}"
# 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
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")
## 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
foo
bar baz
qux
*