我使用以下之一
echo $(stuff)
echo `stuff`
(stuff
例如pwd
或date
或更复杂的地方)。
然后我被告知,这种语法是错误的,是一种错误的做法,不雅致,过多,冗余,过于复杂,不道德的编程,无礼,天真等。
但是该命令确实有效,那么究竟出了什么问题呢?
echo $(echo $(echo $(echo$(echo $(stuff)))))
也可以使用,但您仍然可能不会使用它,对吗?;-)
stuff
。:D
我使用以下之一
echo $(stuff)
echo `stuff`
(stuff
例如pwd
或date
或更复杂的地方)。
然后我被告知,这种语法是错误的,是一种错误的做法,不雅致,过多,冗余,过于复杂,不道德的编程,无礼,天真等。
但是该命令确实有效,那么究竟出了什么问题呢?
echo $(echo $(echo $(echo$(echo $(stuff)))))
也可以使用,但您仍然可能不会使用它,对吗?;-)
stuff
。:D
Answers:
鞋底stuff
将最有可能为你工作。
运行时foo $(stuff)
,会发生以下情况:
stuff
奔跑$(stuff)
在foo
; 的调用中被替换。foo
运行,其命令行参数显然取决于stuff
返回的内容。这种$(…)
机制称为“命令替换”。在您的情况下,main命令echo
基本上将其命令行参数输出到stdout。因此,任何stuff
尝试打印到stdout的东西都会被捕获,传递echo
给stdout并打印到stdout echo
。
如果要将输出输出stuff
到stdout,只需运行sole即可stuff
。
该`…`
语法有异曲同工之妙的$(…)
(在同一个名字:“命令替换”),也有虽然很少差异,所以不能盲目地交换他们。请参阅此常见问题解答和此问题。
echo $(stuff)
无论如何我都应该避免吗?echo $(stuff)
如果您知道自己在做什么,则可能要使用一个原因。出于同样的原因,echo $(stuff)
如果您真的不知道自己在做什么,应该避免使用。
重点是stuff
,echo $(stuff)
而且并不完全相同。后者意味着stuff
在默认值为的输出上调用split + glob运算符$IFS
。用双引号代替命令可以防止这种情况。单引号命令替换使它不再是命令替换。
要在拆分时观察到这一点,请运行以下命令:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
并为:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
如您所见echo "$(stuff)"
,等效于(-ish *)stuff
。您可以使用它,但是以这种方式使事物复杂化的目的是什么?
在另一方面,如果你想要的输出stuff
经过拆分+通配符,那么你可能会发现echo $(stuff)
有用的。但是,这必须是您的自觉决定。
有一些命令生成应评估的输出(包括拆分,globbing等)并由外壳程序运行,因此eval "$(stuff)"
有可能(请参见此答案)。我从来没有见过一个需要它的输出被前进行额外的拆分+通配符命令打印。故意使用echo $(stuff)
似乎很少见。
var=$(stuff); echo "$var"
呢好点子。此代码段:
var=$(stuff)
echo "$var"
应该等价于echo "$(stuff)"
(-ish *)stuff
。如果是完整的代码,请stuff
改为运行。
但是,如果您需要stuff
多次使用输出,则此方法
var=$(stuff)
foo "$var"
bar "$var"
通常比
foo "$(stuff)"
bar "$(stuff)"
即使foo
是echo
并且您echo "$var"
输入了代码,最好还是这样保存。注意事项:
var=$(stuff)
stuff
运行一次; 即使命令很快,避免两次计算相同的输出也是正确的选择。也许stuff
除了写入stdout以外还具有其他效果(例如,创建临时文件,启动服务,启动虚拟机,通知远程服务器),因此您不想多次运行它。stuff
生成依赖时间或随机的输出,您可能会从foo "$(stuff)"
和获得不一致的结果bar "$(stuff)"
。之后var=$(stuff)
的价值$var
是固定的,你可以肯定foo "$var"
,并bar "$var"
得到相同的命令行参数。在某些情况下,foo "$var"
您可能不希望使用()foo $var
,尤其是当stuff
生成多个参数时foo
(如果shell支持,数组变量可能会更好)。再次,知道你在做什么。当谈到echo
的区别echo $var
和echo "$var"
相同之间echo $(stuff)
和echo "$(stuff)"
。
我说echo "$(stuff)"
等同于(-ish)stuff
。至少有两个问题使其不完全等效:
$(stuff)
stuff
在subshell中运行,因此最好说echo "$(stuff)"
等于(-ish)(stuff)
。影响它们在其中运行的shell的命令(如果在子shell中)不会影响主shell。
在这个例子中stuff
是a=1; echo "$a"
:
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
与它比较
a=0
a=1; echo "$a" # stuff
echo "$a"
与
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
再举一个例子,首先stuff
是cd /; pwd
:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
以及测试stuff
和(stuff)
版本。
echo
这不是显示不受控制的数据的好工具。echo "$var"
我们正在谈论的本该是printf '%s\n' "$var"
。但是由于提到了问题,echo
并且因为最可能的解决方案不是一开始就使用echo
,所以我决定在此printf
之前不作介绍。
stuff
或(stuff)
将交错stdout和stderr输出,而echo $(stuff)
将打印来自的所有stderr输出stuff
(首先运行),然后才打印摘要的stdout输出echo
(最后运行)。
$(…)
删除所有结尾的换行符,然后echo
将其重新添加。因此echo "$(printf %s 'a')" | xxd
给出的输出与的输出不同printf %s 'a' | xxd
。
ls
根据标准输出是否是控制台,某些命令(例如)的工作方式有所不同。所以ls | cat
不一样ls
。同样的echo $(ls)
工作方式与ls
。
把ls
放在一边,在一般情况下,如果你非要逼那么这等行为stuff | cat
是优于echo $(ls)
或echo "$(ls)"
因为它不引发其它的所有问题,这里提到。
stuff
方式将交错stdout
和stderr
输出,而echo `stuff`
将打印stderr
来自的所有输出stuff
,然后仅显示stdout
输出。
echo $(stuff)
可能会给您带来更多麻烦,echo "$(stuff)"
好像您不想显式地进行遍历和扩展一样。
$(…)
剥离所有尾随的换行符,然后echo
将其重新添加。因此echo "$(printf %s 'a')" | xxd
给出的输出与的输出不同printf %s 'a' | xxd
。
ls
例如)的工作方式有所不同,具体取决于标准输出是否为控制台。所以ls | cat
不一样ls
。当然,它的echo $(ls)
工作原理将不同于ls
。
另一个区别:子外壳退出代码丢失了,因此echo
取而代之的是退出代码。
> stuff() { return 1
}
> stuff; echo $?
1
> echo $(stuff); echo $?
0
$?
将是echo
(for echo $(stuff)
)的返回码,而不是return
ed 的返回码stuff
。该stuff
函数return 1
(退出代码),但echo
无论的返回代码如何,都将其设置为“ 0” stuff
。仍应在答案中。