bash 无法理解 Fish shell 中的命令替换
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3281220/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot understand command substitution in Fish shell
提问by weakish
In sh:
在 sh:
~$ `echo ls`
bin/ Desktop/
But in fish:
但在鱼中:
fish: Illegal command name “(echo ls)”
~% (echo ls)
(Note that the error message appears above the command line.)
(请注意,错误消息出现在命令行上方。)
~% echo (echo ls)
ls
~% eval (echo ls)
bin/ Desktop/
fish: Illegal command name “(echo ls)”
exec (echo ls)
^
~% exec (echo ls)
It seems that command substitution only works as parameters of a command, not as a command itself? Why?
似乎命令替换仅用作命令的参数,而不是命令本身?为什么?
Well, the help doc does say
嗯,帮助文档确实说
If a parameter contains a set of parenthesis, the text enclosed by the parenthesis will be interpreted as a list of commands.
如果参数包含一组括号,括号内的文本将被解释为命令列表。
But still, why?
但是,为什么?
采纳答案by weakish
How
如何
This because command substitutions belong to parameter expansions and are not allowed as commands.
这是因为命令替换属于参数扩展并且不允许作为命令。
A similar example:
一个类似的例子:
in sh:
在 sh:
tmpls=ls
$tmpls
But in fish:
但在鱼中:
% set cmd ls; $cmd
fish: Variables may not be used as commands.
...
Why
为什么
In short, it's good for verifiability
简而言之,它有利于可验证性
This articleexplains details:
这篇文章解释了详细信息:
Since it is allowed to use variables as commands in regular shells, it is impossible to reliably check the syntax of a script. For example, this snippet of bash/zsh code may or may not be legal, depending on your luck. Do you feel lucky?
if true; then if [ $RANDOM -lt 1024 ]; then END=fi; else END=true; fi; $ENDBoth bash and zsh try to determine if the command in the current buffer is finished when the user presses the return key, but because of issues like this, they will sometimes fail. Even worse, this piece of perfectly legal code is rejected by bash:
FI=fi; foo() { if true; then true; $FI; }Fish avoids this kind of problem, since variables are not allowed as commands. Anything you can do with variables as commands can be done in a much cleaner way using either the eval command or by using functions.
由于在常规 shell 中允许将变量用作命令,因此不可能可靠地检查脚本的语法。例如,这段 bash/zsh 代码可能合法也可能不合法,这取决于您的运气。你觉得幸运吗?
if true; then if [ $RANDOM -lt 1024 ]; then END=fi; else END=true; fi; $ENDbash 和 zsh 都会尝试在用户按下返回键时确定当前缓冲区中的命令是否完成,但由于这样的问题,它们有时会失败。更糟糕的是,这段完全合法的代码被 bash 拒绝了:
FI=fi; foo() { if true; then true; $FI; }Fish 避免了这种问题,因为变量不允许作为命令。可以使用 eval 命令或使用函数以更简洁的方式将变量作为命令执行的任何操作。
For the same reason, command substitutions are not allowed as commands.
出于同样的原因,不允许将命令替换作为命令。
(Note: The cited example is not fair, since 'if' and 'fi' are not simple commands but reserved words. See comments below.)
(注意:引用的例子是不公平的,因为“if”和“fi”不是简单的命令而是保留字。见下面的评论。)
回答by Paused until further notice.
It has to do with the order of expansions.
它与扩展的顺序有关。
From help expand-command-substitutionin fish:
从help expand-command-substitution在fish:
When combining multiple parameter expansions, expansions are performed in the following order:
当组合多个参数扩展时,扩展按以下顺序进行:
* Command substitutions
* Variable expansions
* Bracket expansion
* Pid expansion
* Wildcard expansion
Expansions are performed from right to left, nested bracket expansions are performed from the inside and out.
展开是从右到左进行的,嵌套括号展开是从里到外进行的。
From man bash:
来自man bash:
The order of expansions is: brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion.
扩展的顺序是:大括号扩展、波浪号扩展、参数、变量和算术扩展以及命令替换(以从左到右的方式完成)、分词和路径名扩展。

