![sh 中的函数可以有零个语句吗?](https://linux22.com/image/106959/sh%20%E4%B8%AD%E7%9A%84%E5%87%BD%E6%95%B0%E5%8F%AF%E4%BB%A5%E6%9C%89%E9%9B%B6%E4%B8%AA%E8%AF%AD%E5%8F%A5%E5%90%97%EF%BC%9F.png)
是否有任何相关标准规定 的实现sh
必须对空函数做什么?
以下代码片段定义了一个具有零个语句的函数
a() {
}
子 shell 版本似乎受到相同的对待
a() (
)
ash
并zsh
接受任一构造作为不执行任何操作且退出状态为零的函数。
ksh
( ksh93
) 并且bash
都拒绝该函数作为语法错误
$ a() {
> }
ksh: syntax error: `}' unexpected
和 bash
bash-4.4$ a() {
> }
bash: syntax error near unexpected token `}'
答案1
不,在符合要求的应用程序中,函数的大括号之间不能有空函数体。
POSIX定义函数定义命令作为:
fname ( ) compound-command [io-redirect ...]
其中所有这些单词都是规范中其他地方定义的事物的占位符。compound-command
是函数体。
A复合命令被定义为作为几个项目之一,包括循环、条件和 case 语句,但这里最相关的是A分组命令,在两种情况下定义:
( compound-list )
在子shell环境中执行compound-list;请参阅 Shell 执行环境。影响环境的变量分配和内置命令在列表结束后不应继续有效。 (...关于算术展开式的段落被省略了...)
{ compound-list ; }
在当前进程环境中执行compound-list。此处显示的分号是分隔 } 保留字的控制运算符的示例。其他分隔符也是可能的,如 Shell 语法中所示; <newline> 经常使用。
如果可以是空的,那么空的{\n}
身体就是有效的。compound-list
这外壳语法进而定义了shell命令语言的解析规则,包括化合物列表:
compound_list : linebreak term | linebreak term separator
这意味着复合列表要么linebreak
后跟 a term
,要么linebreak
后跟 aterm
和 a separator
。separator
是;
或&
.linebreak
是一个可能为空的换行序列。所以如果可以为空的话这也可以为空term
。
term
是:
term : term separator and_or | and_or
和and_or
:
and_or : pipeline | and_or AND_IF linebreak pipeline | and_or OR_IF linebreak pipeline
最后两行覆盖&&
和||
。是由字符分隔的 spipeline
的非空序列。是简单命令、复合命令或函数定义。因此,如果简单命令或复合命令可以为空,则 、 和 可以为空。command
|
command
term
command
cmd_name
简单命令始终包含、cmd_word
或之一cmd_prefix
。cmd_prefix
是重定向或分配,可以选择附加到另一个前缀。另外两个都分解为WORD
,语法中的一个标记,它是单词字符的非空序列。所以一个简单的命令永远不会是空的。
我们已经研究过复合命令,但这次让我们从语法的角度回顾一下。复合命令是大括号组、子 shell、for
、while
或until
循环、 andif
或 之一case
。所有这些都至少包含一个固定词(如“ for
”)或一个(
或。{
因此复合命令永远不会为空。
因此 acommand
永远不会为空,因此也pipeline
永远不会为空,也不是and_or
、term
或compound_list
。这意味着
{
}
是不允许的,所以函数定义
a() {
}
也无效。
以上所有内容都适用于一致的、可移植的 shell 脚本。zsh
并且ash
可以自由地扩展他们的实现来处理否则无效的脚本,无论他们想要什么,他们选择的实现似乎是明智和方便的。 Bash、ksh、dash 和其他工具采取了更简约的路线来实现所需的功能。所有这些都是一致的选择。
可移植脚本始终需要提供非空函数体,但单独针对(例如)zsh 的脚本则不需要。
答案2
听起来您对各种 shell 的语法树感兴趣。这是 bash 的相关部分:https://www.gnu.org/software/bash/manual/bashref.html#Shell-Syntax
函数定义为[1]:
使用以下语法声明函数:
name () compound-command [ redirections ]
或
function name [()] compound-command [ redirections ]
您感兴趣的部分是compound-command
,它可以是以下之一 [2]:
• 循环构造:用于迭代操作的Shell 命令。
• 条件结构:用于条件执行的Shell 命令。
• 命令分组:对命令进行分组的方法。
{}
和语法()
是 a command grouping
,可以是以下之一 [3]:
( list )
{ list; }
Alist
定义为 [4]:
列表是由运算符
‘;’
、‘&’
、‘&&’
或之一分隔的一个或多个管道的序列,并且可以选择以、或换行符‘||’
之一终止。‘;’
‘&’
Apipline
定义为 [5]:
管道是由一个控制运算符
‘|’
或分隔的一个或多个命令的序列‘|&’
。
您的函数示例包含一个复合命令,该命令必须包含一个或多个pipelines
,每个命令又包含一个或多个commands
。
因此,在 bash 中,您的函数中必须至少有一个命令。其他 shell 可能类似,并且也有可用的语法指南。
如果出于某种原因您想要一个不执行任何操作的函数,您可以使用 Bash 的内置占位符,即:
它不会成功执行任何操作。
a(){:}
答案3
这是 bash 得到的最接近空的结果:
a (){
:
}