在sh:
~$ `echo ls`
bin/ Desktop/
但在鱼:
fish: Illegal command name “(echo ls)”
~% (echo ls)
(请注意,错误消息显示在命令行上方。)
~% echo (echo ls)
ls
~% eval (echo ls)
bin/ Desktop/
fish: Illegal command name “(echo ls)”
exec (echo ls)
^
~% exec (echo ls)
命令替换似乎只作为命令的参数,而不是命令本身?为什么呢?
嗯,帮助文档说的是
如果参数包含一组括号,则括号括起的文本将被解释为命令列表。
但是,为什么呢?
答案 0 :(得分:4)
这是因为命令替换属于参数扩展,不允许作为命令。
一个类似的例子:
在sh:
tmpls=ls
$tmpls
但在鱼:
% set cmd ls; $cmd
fish: Variables may not be used as commands.
...
简而言之,它对可验证性有好处
这article解释了详细信息:
由于允许在常规shell中使用变量作为命令,因此无法可靠地检查脚本的语法。例如,这段bash / zsh代码可能合法也可能不合法,具体取决于您的运气。你觉得幸运吗?
if true; then if [ $RANDOM -lt 1024 ]; then END=fi; else END=true; fi; $END
当用户按下返回键时,bash和zsh都会尝试确定当前缓冲区中的命令是否已完成,但由于此类问题,它们有时会失败。更糟糕的是,这段完全合法的代码被bash拒绝了:
FI=fi; foo() { if true; then true; $FI; }
Fish避免了这种问题,因为变量不允许作为命令。使用eval命令或使用函数,可以使用变量作为命令执行的任何操作都可以更清晰地完成。
出于同样的原因,命令替换不允许作为命令。
(注意:引用的例子不公平,因为'if'和'fi'不是简单的命令而是保留字。请参阅下面的评论。)
答案 1 :(得分:0)
它与扩展的顺序有关。
来自help expand-command-substitution
中的fish
:
组合多个参数扩展时,会执行扩展 按以下顺序:
* Command substitutions
* Variable expansions
* Bracket expansion
* Pid expansion
* Wildcard expansion
从右到左执行扩展,嵌套括号扩展 从内到外进行。
来自man bash
:
扩展的顺序是:括号扩展,波浪扩展,参数,变量和算术扩展以及命令替换(完成 以从左到右的方式),单词拆分和路径名扩展。