Bash脚本使用变量不遵守引号

时间:2018-07-13 07:36:07

标签: bash shell

我的目标是使用变量作为参数来调用脚本。例如,我有以下两个文件:

print_args.sh:
    echo "Length: $#"
    for i in "$@"; do echo "$i"; done

caller.sh:
    ARGS="foo \"Hello, World\" bar"
    ./test.sh $ARGS

当我跑步时:

./print_args.sh foo "Hello, World" bar

print_args.sh的调用带有3个参数:

Length 3
foo
Hello, World
bar

但是,当通过caller.sh运行它时,我得到了4个参数:

Length: 4
foo
"Hello,
World"
bar

这是怎么回事?如何使caller.sh达到预期效果?

注意:我无法控制它作为环境变量传入的ARGS

1 个答案:

答案 0 :(得分:3)

  

如何使test_caller.sh达到预期效果?

使用数组:

#!/bin/bash

args=( foo "Hello, World" bar )
./test.sh "${args[@]}"

如果传递未加引号的变量,则在将其传递给./test.sh之前,会在其内容上进行单词拆分。您实际上是在打电话:

'./test.sh' 'foo' '"Hello,' 'World"' 'bar'

其中的单引号用于指示单词的开头和结尾。双引号没有语法含义,此时它们只是字符串中的字符。


如果您可以说服脚本用户更改环境变量的格式,则可以基于其他分隔符对其进行拆分:

ARGS="foo:Hello World:bar"
set -f # disable glob expansion
IFS=: args=( $ARGS )
set +f # re-enable it

现在您有了一个数组args,可以像上面那样使用。


将字符串放入数组的一种(非常讨厌,危险)方法是使用臭名昭著的eval

readarray -t args < <(eval printf '%s\\n' $ARGS)

现在您有了一个数组args,可以像前面的示例中那样使用它。

但这是一个很大的安全问题:

ARGS="foo \"Hello, World\" bar \$(ls -l)"

用您要执行的任何命令替换ls -l ...