我有一个大脚本(称之为test
),在删除不相关的部分之后,归结为使用我可以解释我的问题:
#!/bin/bash
bash -c "$@"
这并不像预期的那样有效。例如。 ./test echo hi
只执行echo
,参数消失!
使用各种输入进行测试我只能看到$1
传递给bash -c ...
而其余的被丢弃。
但如果我使用像:
这样的变量#!/bin/bash
cmd="$@"
bash -c "$cmd"
它可以按预期运行所有输入。
问题:
1)我想理解为什么双引号没有通过" bash -c ...
的整个命令行参数。我在这里缺少什么(当使用中间变量时它完全正常)?
2)为什么bash在没有任何错误消息的情况下丢弃其余参数($1
除外)?
例如:
bash -c "ls" -l -a hi hello blah
只需运行echo
而hi hello blah
根本不会导致任何错误?
(如果可能,请参阅记录此行为的bash语法。)
答案 0 :(得分:1)
您应该使用$*
而不是$@
来将命令行作为字符串传递。 "$@"
扩展为多个带引号的参数,"$*"
将多个参数组合成一个参数。
#!/bin/bash
bash -c "$*"
问题在于你执行的$@
:
bash -c echo hi
但是$*
会执行:
bash -c 'echo hi'
使用时:
cmd="$@"
并使用:bash -c "$cmd"
它对你做同样的事情。
答案 1 :(得分:1)
1)我想理解为什么双引号不会将整个命令行参数“传递”给bash -c ....我在这里缺少什么(使用中间变量时它完全正常) ?
来自info bash @
:
@
($@
)从1开始扩展到位置参数。当扩展发生在双引号内时,每个参数都会扩展 一个单独的词。也就是说,"$@"
相当于"$1" "$2" ...
。
因此,bash -c "$@"
相当于bash -c "$1" "$2" ...
。在./test echo hi
调用的情况下,表达式扩展为
bash -c "echo" "hi"
2)为什么bash在没有任何错误消息的情况下丢弃其余参数($ 1除外)?
Bash实际上并没有丢弃任何东西。来自man bash
:
如果存在
-c
选项,则从第一个非选项参数command_string
读取命令。如果在command_string
之后存在参数,则会将它们分配给位置参数,从$0
开始。
因此,对于命令bash -c "echo" "hi"
,Bash将"hi"
作为$0
传递给"echo"
脚本。
bash -c "ls" -l -a hi hello blah
只需运行echo,你好,你好blah不会导致任何错误吗?
根据上述规则,Bash执行"ls"
脚本并将以下位置参数传递给此脚本:
$0
:"-l"
$1
:"-a"
$2
:"hi"
$3
:"hello"
$4
:"blah"
因此,该命令实际执行ls
,并且脚本中的位置参数 unused 。您可以通过参考位置参数来使用它们,例如:
$ set -x
$ bash -c "ls \$0 \$1 \$3" -l -a hi hello blah
+ bash -c 'ls $0 $1 $3' -l -a hi hello blah
ls: cannot access hello: No such file or directory