为什么不允许数字函数名称?


10

考虑以下:

$ ksh -c '1(){ echo hi;};1'
ksh: 1: invalid function name
$ dash -c '1(){ echo hi;};1'
dash: 1: Syntax error: Bad function name
$ bash -c '1(){ echo hi;};1'
bash: `1': not a valid identifier
bash: 1: command not found
$ mksh -c '1(){ echo hi;};1'
hi

基本上,我试图声明函数10这将是true和的简写false,但是如您所见,我在函数中使用数字名称时遇到了问题。别名和两位数名称也会发生相同的行为。

问题是“为什么”?它是POSIX授权的吗?或只是一个类似本恩的贝壳怪癖?

另请参阅相关的问题


1
posix强制执行的操作通常是类似Bourne的shell的怪癖。:P
大师

我看你在那儿干了什么。。。> :)大声笑
Sergiy Kolodyazhnyy

4
@fkraiem请参考meta.askubuntu.com/q/13807/295286 Shell / shell脚本一直是Ask Ubuntu的主题:)这是对任何Ubuntu系统进行正确系统管理的重要主题
Sergiy Kolodyazhnyy

4
值得注意的是,它0true在shell脚本中编写1false(实际上,任何非零值都将被视为false),以防万一有人读到它。这与大多数其他编程语言相反。
伊桑·卡明斯基

2
@EthanKaminski是的,就命令的退出状态而言,这是绝对正确的。返回值0 true在shell中。但是,在算术扩展中,$((...))返回状态被翻转-1为true,0 false为与C语言语法一致。例如bash -c 'echo $((1==1));echo $((1==2))' ,尝试在此问题之外进行的操作实际上是“逆转”该行为。看到最后例如在我的答案在这里,看看究竟是什么,我试图做的。愚蠢的想法,但仍然有效
Sergiy Kolodyazhnyy

Answers:


14

POSIX说:

2.9.5功能定义命令

函数是用户定义的名称,用作简单命令以使用新的位置参数调用复合命令。通过“功能定义命令”定义功能。

函数定义命令的格式如下:

 fname ( ) compound-command [io-redirect ...]

该函数名为fname;应用程序应确保它是一个名称(请参见XBD Name),并且不是特殊内置实用程序的名称。一个实现可以允许函数名称中的其他字符作为扩展名。实现应为函数和变量维护单独的名称空间。

和:

3.235名称

在Shell命令语言中,是仅由可移植字符集中的下划线,数字和字母组成的单词。名称的第一个字符不是数字。

注意:可移植字符集在“可移植字符集”中详细定义。

因此,以数字开头的单词不能是函数名称。


POSIX仍未完全说明原因,但我将其视为“因为标准”答案。谢谢
Sergiy Kolodyazhnyy

4
@SergiyKolodyazhnyy我会说这是继承的东西。这个名称标准在其他方面也很常见(IIRC C名称也遵循相同的标准),因此可能是Unix的问题。此外,在C语言中,解析起来也更容易
muru

3
如果允许使用@muru在C语言中会带来一些歧义。例如什么1L意思?函数名称?还是long int文字?
Ruslan

2
另外,值得注意的是,在C语言中,裸函数名称可以充当该函数的指针。这使您可以将函数作为参数传递给函数,将对它们的引用存储在变量中,等等。通常用于回调。()与之相反的是函数名称,后跟,可能带有内部参数,这表示对所讨论函数的调用(并采用被调用函数返回的值)。因此,如果您int f() { return 42; }在C中有一个函数,f则在指针上下文f()中有效,并且在非指针整数上下文中有效。
CVn

13

这是许多语言的标准,以防止数学运算与变量或函数或方法之间的混淆。

考虑:

var 1 = 100

print 1*10 //should return 10 but would instead return 1000

var x = 5
x += 1
print x //returns 105, not 6    

def 100(num)
  return num * 1000
end

var y = 10 + 100(10)
print y // returns 100010 instead of 1010

如您所见,如果允许数字作为变量或函数名称,则稍后在程序中进行数学运算可能会变得非常混乱,如果以后需要对这些数字进行数学运算,则必须提出创造性的解决方法。在某些语言中,它也会产生意想不到的结果。假设您要为循环增加一个数字,但数字之一已经是一个等于字符串的变量。它将立即引发错误。如果您不是该代码的原始作者,那么可能需要一段时间才能找到该错误。

简而言之,这就是为什么大多数语言都不允许您使用数字作为变量,函数或方法等的名称的原因。


我本来要评论“但必须在shell中添加变量才能进行$扩展”,但是如果shell受其他语言的启发,那就可以了,我想这是可以的,再加上算术扩展中的((变量也不需要具有前导$。好吧,我能理解
Sergiy Kolodyazhnyy

3
是的,这是一个约定,因为它会在几乎所有语言中产生意外的结果,但是,即使在可行的情况下,对于任何需要在您之后处理您的代码的人来说,它也会使代码很难理解。
乔什(Josh)

2
@SergiyKolodyazhnyy算术扩展允许不带引用变量名$,因此就可以了。但这可能只是“遵循共同惯例”的另一个原因的第二个原因
霍布斯

@hobbs是,绝对同意
Sergiy Kolodyazhnyy

1
对于外壳,这种“大多数语言”的解释几乎没有意义。所有的Bourne式炮弹有参数的名字看起来像数字文字或运营商:0对于壳或脚本名称,12,...,为位置参数,*为他们加盟,-为启用的选项,?最后退出状态,并!为最新异步作业的PID。(因此,即使在$(( ))$也经常需要。)此处显示的代码用来证明建议的基本原理不是任何Bourne风格的shell的脚本,因为无法以这种方式进行演示,因为它不适用于他们。
伊利亚·卡根

10

在C中,考虑如下表达式:

1000l + 2.0f;

1000l变量还是常量?由于变量名不能以数字开头,因此必须为常量。这样可以使解析更加轻松和严格(1000k很容易捕获打字错误)。对于变量和函数名称使用单一规则也更容易,因为函数也可以视为变量。当然,现在解析器要复杂得多且功能强大,并且我们拥有C ++中的自定义文字。但是,在史前时代的远古时代,牺牲一点不必要的灵活性可能会使您的编译(或解释)时间缩短很多(而且人们仍然抱怨C ++编译时间)。

而且您会看到C影响力在整个Shell语言中的影响,因此Bourne Shell(或C Shell)以及POSIX将允许名称的类别限制为与C相同就不足为奇了。


2
可以解释,这是正确的。这并不是说所有语言都适用相同的考虑因素,也不是说Bourne风格的shell具有与C相似的语法,而是与C相关的文化很强,shell设计人员必须对要使用的标识符提出一些保证。允许的。我认为这可以使用“您可以在整个Shell语言中看到C的影响的效果”的示例,因为它们之间的相似性实际上并没有超过差异(例如,考虑哪些数字被认为是正确的)。尽管如此,这个答案是正确的。
伊莱亚·卡根

@Eliah可以说数字问题也是C语言成功和失败的退出状态的直接结果,因此在编写Shell测试时,我倾向于从成功和失败的角度考虑,而不是对与错。您说对了,因为许多Shell语法都不像C,但是示例包括花括号,分号,短路&&||缺少对字符串中ASCII nul的支持,
Olorin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.