Kam*_*ski 35 sh shell-script echo
我使用了以下之一
echo $(stuff)
echo `stuff`
Run Code Online (Sandbox Code Playgroud)
(stuff例如pwd或date或更复杂的东西在哪里)。
然后我被告知这种语法是错误的,一种不好的做法,不优雅,过度,多余,过于复杂,货物崇拜编程,noobish,天真等等。
但是该命令确实有效,那么它到底有什么问题呢?
Kam*_*ski 67
鞋底stuff很可能对你有用。
当您运行时foo $(stuff),会发生以下情况:
stuff 在子shell中执行,设置它需要一些时间;$(stuff)为foo;的参数。Stderr 仍会转到 /dev/stderr。stuff和通过捕获$(...),如在不引,是受通配和分裂。<space><tab><newline>。*,?并有效的[]将与被替换列表的匹配文件。foo运行,它的命令行参数显然取决于stuff返回的内容。这种$(…)机制称为“命令替换”。在您的情况下,主命令echo基本上将其命令行参数打印到由单个空格分隔的标准输出。因此,任何stuff尝试打印到标准输出的内容都会被捕获、修改、扩展并提供给echo,然后通过echo.
如果您希望将 的输出stuff打印到标准输出,只需运行唯一的stuff.
该`…`语法有异曲同工之妙的$(…)(在同一个名字:“命令替换”),也有虽然很少差异,所以不能盲目地交换他们。请参阅此常见问题解答和此问题。
echo $(stuff)无论如何我应该避免吗?echo $(stuff)如果您知道自己在做什么,那么您可能想要使用它是有原因的。出于同样的原因,echo $(stuff)如果您真的不知道自己在做什么,则应该避免。
关键是stuff并且echo $(stuff)绝不是等价的。后者意味着在 的输出上调用 split+glob 运算符,stuff默认值为$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")'
Run Code Online (Sandbox Code Playgroud)
对于通配:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Run Code Online (Sandbox Code Playgroud)
如您所见echo "$(stuff)",相当于(-ish*) 到stuff. 您可以使用它,但是以这种方式使事情复杂化有什么意义呢?
另一方面,如果您希望的输出stuff进行拆分+通配,那么您可能会发现echo $(stuff)很有用。不过,这必须是你有意识的决定。
有一些生成输出的命令应该被评估(包括拆分、通配等)并由 shell 运行,所以eval "$(stuff)"是一种可能性(请参阅此答案)。我从未见过需要其输出在打印之前进行额外拆分+通配的命令。故意使用echo $(stuff)似乎非常罕见。
var=$(stuff); echo "$var"?好点子。这个片段:
var=$(stuff)
echo "$var"
Run Code Online (Sandbox Code Playgroud)
应该等价于echo "$(stuff)"(-ish*)到stuff. 如果是整个代码,只需运行即可stuff。
但是,如果您需要stuff多次使用输出,则此方法
var=$(stuff)
foo "$var"
bar "$var"
Run Code Online (Sandbox Code Playgroud)
通常比
foo "$(stuff)"
bar "$(stuff)"
Run Code Online (Sandbox Code Playgroud)
即使foo是echo并且您进入echo "$var"了您的代码,最好保持这种方式。需要考虑的事项:
var=$(stuff) stuff运行一次; 即使命令很快,避免两次计算相同的输出也是正确的。或者可能stuff除了写入标准输出之外还有其他影响(例如,创建临时文件、启动服务、启动虚拟机、通知远程服务器),因此您不想多次运行它。stuff生成依赖于时间或有些随机的输出,您可能会从foo "$(stuff)"和得到不一致的结果bar "$(stuff)"。之后var=$(stuff)的价值$var是固定的,你可以肯定foo "$var",并bar "$var"得到相同的命令行参数。在某些情况下,foo "$var"您可能希望(需要)使用foo $var,而不是使用,尤其是在为(如果您的 shell 支持数组变量可能会更好)stuff生成多个参数时foo。再次,知道你在做什么。当谈到echo的区别echo $var和echo "$var"相同之间echo $(stuff)和echo "$(stuff)"。
我说echo "$(stuff)"相当于(-ish)到stuff. 至少有两个问题使它不完全等效:
$(stuff)stuff在子shell中运行,所以最好说echo "$(stuff)"是等价的(-ish)到(stuff). 影响它们运行的 shell 的命令,如果在子 shell 中,不会影响主 shell。
在这个例子中stuff是a=1; echo "$a":
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Run Code Online (Sandbox Code Playgroud)
比较一下
a=0
a=1; echo "$a" # stuff
echo "$a"
Run Code Online (Sandbox Code Playgroud)
与
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Run Code Online (Sandbox Code Playgroud)
再比如,开始stuff是cd /; pwd:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
Run Code Online (Sandbox Code Playgroud)
和测试stuff和(stuff)版本。
echo不是显示不受控制的数据的好工具。这echo "$var"我们谈论应该是printf '%s\n' "$var"。但是既然提了这个问题echo,而且最有可能的解决方案是一开始就不使用echo,所以我决定暂时不做介绍printf。
stuffor(stuff)将交错 stdout 和 stderr 输出,同时echo $(stuff)将打印stuff(首先运行)的所有 stderr 输出,然后才打印由(最后运行)消化的 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)"因为它不引发其它的所有问题,这里提到。
另一个区别:子shell退出代码丢失,因此echo取而代之的是退出代码。
> stuff() { return 1
}
> stuff; echo $?
1
> echo $(stuff); echo $?
0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5548 次 |
| 最近记录: |