从命令行传递字符串时的Bash怪癖
这是我创建的一个示例,用于演示这种奇怪的行为。 我希望bash按原样传递引用的命令行参数从命令行传递字符串时的Bash怪癖,bash,shell,scripting,sh,Bash,Shell,Scripting,Sh,这是我创建的一个示例,用于演示这种奇怪的行为。 我希望bash按原样传递引用的命令行参数 john@doe:~/tmp$ cat script.sh #! /bin/bash set -o xtrace $1 sleep 3 john@doe:~/tmp$ ./script.sh "echo" + echo sleep 3 sleep 3 john@doe:~/tmp$ ./script.sh "echo -n" + echo -n sleep 3 sleep 3john@doe:~/tmp$
john@doe:~/tmp$ cat script.sh
#! /bin/bash
set -o xtrace
$1 sleep 3
john@doe:~/tmp$ ./script.sh "echo"
+ echo sleep 3
sleep 3
john@doe:~/tmp$ ./script.sh "echo -n"
+ echo -n sleep 3
sleep 3john@doe:~/tmp$
但有时bash会编辑我的字符串参数,并在符号周围添加记号
喜欢或&&
john@doe:~/tmp$ ./script.sh "echo hello ;"
+ echo hello ';' sleep 3
hello ; sleep 3
john@doe:~/tmp$ ./script.sh "echo hello && "
+ echo hello '&&' sleep 3
hello && sleep 3
这个bash规则是什么?如何规避它?非常感谢:)规则是引用元字符,否则会有不同的解释。分号是语句分隔符,与
&&
一样。引用可以方便地剪切和粘贴特定行,并使其重现原始效果
想想这两者的区别
echo hello '&&'
对
echo hello &&
第一个回显两个单词,第二个等待更多输入。您称之为quirky的引用按照设计工作,是您真正想要的,不,除了黑客bash源代码之外,没有其他方法可以绕过它。手册中概述了规则: 你会看到: 以下是shell在运行时的操作的简要说明 读取并执行命令。基本上,shell执行以下操作:
-c
调用选项(请参阅)的字符串或用户终端读取其输入#! /bin/bash
$1 sleep 3
执行/script“echo hello;”
时会发生什么
代码>这是在你的论点回声你好代码>。
此时,它只看到三个令牌$1
、sleep
和3
$1
被扩展为echo
、hello
和代码>(这里的分号并不是一个参数,它不被理解为控制运算符,因为控制运算符的扫描已在步骤2中完成,将不再执行)
echo
,代码>,睡眠
和3
。因此,它愉快地回响着你好;睡眠3
echo
后收集退出状态(很可能成功)eval
,但这很危险,并且有很多警告:用
#!/bin/bash
eval "$1 sleep 3"
使用此脚本:
$ ./script "echo hello;"
hello
$
(延迟3秒后显示最终提示)。同样适用于/script“echo hello&&”
但这不是一个好主意。请继续阅读
一般来说,您应该避免(至少在Bash中)混合数据和代码:变量用于保存数据(字符串),而不是代码。所以这不是一个好方法。我说这不是一个好方法,不仅是因为有人曾经说过不应该将数据与代码混合,而且因为如果你开始在“代码”中使用特殊字符,它将变得不可用。例如,如果要回显*
符号,则必须使用笨拙的调用/script“echo\”*\;“
”。还有很多其他的警告
代码保存在函数或脚本中。使用函数:
say_hello_and_execute() {
echo hello; "$@"
}
然后导出此函数:export-f say_hello_and_execute
,并将其用作脚本的参数:/script say_hello_and_execute
脚本也可以实现同样的效果:调用以下脚本说“你好”和“执行”
:
#!/bin/bash
echo hello; "$@"
然后chmod+x说你好并执行
并以/script./say你好并执行
的形式运行脚本
这个答案试图回答你的问题。不过,如果您能准确地告诉我们您想要实现什么,那就更好了,因为可能会有更好的设计来实现这一点。很明显,示例应该有单引号,而不是反引号。感谢您全面的回答!(和gnu参考)。我发现我走错了方向。