了解 bash 令牌替换的限制

了解 bash 令牌替换的限制

bash 有标记替换,可以通过语法$(),也可以通过``语法,例如:

$ $(echo "echo hi")
hi

AFAIK,工作原理如下:

  • 首先评估内部命令:echo "echo hi",其输出echo hi
  • 然后将结果字符串作为命令执行echo hi,这会产生hi

既然如此,我希望将以下内容写入hi文件/tmp/hi

$ $(echo "echo hi > /tmp/hi")

相反,它不会向任何文件写入任何内容,并输出:

hi > /tmp/hi

这里发生了什么?我最初认为这可能是因为字符串中有空格,但以下内容否定了该理论:

$ $(echo "echo hi bob")
hi bob

答案1

bash适用于您的情况的手册部分是这样的:

简单的命令扩展

当执行一个简单的命令时,shell 从左到右执行以下扩展、赋值和重定向。

  1. 解析器标记为变量赋值(命令名称前面的那些)和重定向的单词是保存以供以后处理

  2. 不是变量赋值或重定向的单词会被扩展。如果扩展后仍有任何单词,则第一个单词将被视为命令名称,其余单词将被视为参数。

  3. 重定向按照上面“重定向”下的描述执行。

  4. 每个变量赋值中 = 后面的文本在赋值给变量之前都会经历波形符扩展、参数扩展、命令替换、算术扩展和引号删除。

您的$(echo "echo hi > /tmp/hi")命令替换将在第 2 点展开,并且由于>无法在第 1 点将重定向标记为稍后处理(因为它仅作为命令替换的结果出现),因此不会按照第 3 点执行。

如果在扩展之前没有对重定向进行预处理,那么类似

to='>'; echo foo $to bar

将回显foo到文件中bar,而不是foo > bar像它那样仅仅回显。

请注意,它bash与其他 shell 的不同之处在于,它还在重定向运算符后面的单词上执行 split + globbing(如果扩展为多个单词,则会因“不明确的重定向”而死亡)。例如,这个

var='a b'; echo > $var

将会出错,bash而不是破坏一个名为的文件a b(就像其他 shell 一样)。

相关内容