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 从左到右执行以下扩展、赋值和重定向。
解析器标记为变量赋值(命令名称前面的那些)和重定向的单词是保存以供以后处理。
不是变量赋值或重定向的单词会被扩展。如果扩展后仍有任何单词,则第一个单词将被视为命令名称,其余单词将被视为参数。
重定向按照上面“重定向”下的描述执行。
每个变量赋值中 = 后面的文本在赋值给变量之前都会经历波形符扩展、参数扩展、命令替换、算术扩展和引号删除。
您的$(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 一样)。