POSIX shell 语法http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_10_02
说
pipe_sequence : command
| pipe_sequence '|' linebreak command
;
command : simple_command
| compound_command
| compound_command redirect_list
| function_definition
这意味着,函数定义可以是管道序列中的一个术语。这怎么可能呢?函数定义不能有标准输入或输出,它也不是可以执行的命令。只有函数称呼,这是一个简单的命令,可以执行。
在第一条评论和答案之后添加:
function_definition
如果我们从这里分离出来command
,并将其作为另一种替代方案添加到其他command
出现的位置,那么是的,我们正在使语法变得有点复杂。
但其回报更为重要:这种 shell 的实现更加容易。
因为如果你允许在管道中定义函数,你就必须处理诸如函数的作用域是什么、它在什么环境中运行等问题。我认为标准中根本没有回答这些问题。
更糟糕的是:语法稍微复杂一点,还是实施者的工作量和复杂性增加很多。如果是前者,那么这不就是“本末倒置”的例子吗?
答案1
事实上更轻松实施者不必担心这一点。执行管道时,每个组件都在其自己的子 shell 中运行(除了 bash 中的第一个,或者如果命令是本机命令,则在 ksh88/ksh93 中的最后一个)。因此,管道中间的函数定义将为管道该组件的 shell 实例定义,但在外部不可见……这一切都是基于管道语义自动完成的。
如果您想要阻止cd
管道内的函数定义(或别名定义,或诸如...之类的愚蠢命令),那么您就使实现变得复杂了:-)
答案2
为什么不可能?这毫无意义吗?当然。但它确实有效:
$ function asdf { echo "bla"; } | hexdump -C; echo EOF
EOF
相似地:
$ function asdf { echo "bla"; } | asdf | hexdump -C; echo EOF
-bash: asdf: command not found
EOF
定义函数和其他命令一样,都是“命令”。不过,它没有任何输出,也不接受任何输入。你甚至可以进行变量赋值。当然,这又毫无意义,但不是错误。
“为什么”可能是:KISS。你不会想用不必要的复杂性来污染你的语法。
更新:经过进一步检查,我发现 Bash 甚至懒得在函数定义之后运行管道命令。