sh 中的函数可以有零个语句吗?

sh 中的函数可以有零个语句吗?

是否有任何相关标准规定 的实现sh必须对空函数做什么?

以下代码片段定义了一个具有零个语句的函数

a() {
}

子 shell 版本似乎受到相同的对待

a() (
)

ashzsh接受任一构造作为不执行任何操作且退出状态为零的函数。

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 separatorseparator;&.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|commandtermcommand

cmd_name简单命令始终包含、cmd_word或之一cmd_prefixcmd_prefix是重定向或分配,可以选择附加到另一个前缀。另外两个都分解为WORD,语法中的一个标记,它是单词字符的非空序列。所以一个简单的命令永远不会是空的。

我们已经研究过复合命令,但这次让我们从语法的角度回顾一下。复合命令是大括号组、子 shell、forwhileuntil循环、 andif或 之一case。所有这些都至少包含一个固定词(如“ for”)或一个(或。{因此复合命令永远不会为空。

因此 acommand永远不会为空,因此也pipeline永远不会为空,也不是and_ortermcompound_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 (){  
  :   
}

相关内容