无法理解Fish shell中的命令替换

时间:2010-07-19 13:02:03

标签: bash shell command-line fish

在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)

命令替换似乎只作为命令的参数,而不是命令本身?为什么呢?

嗯,帮助文档说的是

  

如果参数包含一组括号,则括号括起的文本将被解释为命令列表。

但是,为什么呢?

2 个答案:

答案 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

  

扩展的顺序是:括号扩展,波浪扩展,参数,变量和算术扩展以及命令替换(完成          以从左到右的方式),单词拆分和路径名扩展。