Bash中有效标识符(例如函数,变量等)的规则是什么?

问题描述 投票:21回答:5

Bash中标识符的语法规则是什么,特别是函数和变量名?

我写了一个Bash脚本并在Ubuntu,Debian,Red Hat 5和6上的各种版本的Bash上测试了它,甚至是一个旧的Solaris 8盒子。脚本运行良好,所以发货了。

然而,当用户在SUSE机器上尝试它时,它给出了“非有效标识符”错误。幸运的是,我猜测函数名中有一个无效字符是正确的。连字符弄乱了它。

事实上,至少在某种程度上经过测试的脚本在另一个Bash或发行版上会有完全不同的行为,这令人不安。我怎么能避免这个?

linux bash unix syntax
5个回答
22
投票
   Shell Function Definitions
       ...
       name () compound-command [redirection]
       function name [()] compound-command [redirection]

name在其他地方定义:

       name   A  word  consisting  only  of alphanumeric characters and under‐
              scores, and beginning with an alphabetic character or an  under‐
              score.  Also referred to as an identifier.

所以连字符无效。然而,在我的系统上,他们确实工作......

$ bash --version
GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)

7
投票

命令标识符和变量名称具有不同的语法。变量名称仅限于字母数字字符和下划线,不以数字开头。另一方面,命令名可以是任何不包含bash元字符的东西(即便如此,它们也可以被引用)。

在bash中,函数名称可以是命令名称,只要它们被解析为没有引号的WORD即可。 (除此之外,由于某种原因,它们不能是整数。)但是,这是一个bash扩展。如果目标机器正在使用其他shell(例如破折号),则它可能不起作用,因为Posix标准shell语法仅在函数定义表单中允许“NAME”(并且还禁止使用保留字)。


6
投票

问题是关于“规则”,它已经以两种不同的方式回答,每种方式在某种意义上都是正确的,这取决于你想要称之为“规则”的东西。只是为了充实@ rici的观点,你可以推动函数名中的任何字符,我写了一个小的bash脚本,试图检查每个可能的(0-255)字符作为函数名,以及作为第二个字符功能名称:

#!/bin/bash
ASCII=( nul soh stx etx eot enq ack bel bs tab nl vt np cr so si dle \
            dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us sp )

for((i=33; i < 127; ++i)); do
    printf -v Hex "%x" $i

    printf -v Chr "\x$Hex"
    ASCII[$i]="$Chr"
done
ASCII[127]=del
for((i=128; i < 256; ++i)); do
    ASCII[$i]=$(printf "0X%x" $i)
done

# ASCII table is now defined

function Test(){
    Illegal=""
    for((i=1; i <= 255; ++i)); do
        Name="$(printf \\$(printf '%03o' $i))"
        eval "function $1$Name(){ return 0; }; $1$Name ;" 2>/dev/null
        if [[ $? -ne 0 ]]; then
            Illegal+=" ${ASCII[$i]}"
            #        echo Illegal: "${ASCII[$i]}"
        fi
    done
    printf "Illegal: %s\n" "$Illegal"
}
echo "$BASH_VERSION"
Test
Test "x"

# can we really do funky crap like this?
function [}{(){
   echo "Let me take you to, funkytown!"
}
[}{    # why yes, we can!
# though editor auto-indent modes may punish us

我实际上跳过NUL(0x00),因为这是一个字符bash可能反对在输入流中查找。该脚本的输出是:

4.4.0(1)-release
Illegal:  soh tab nl sp ! " # $ % & ' ( ) * 0 1 2 3 4 5 6 7 8 9 ; < > \ ` { | } ~ del
Illegal:  soh " $ & ' ( ) ; < > [ \ ` | del
Let me take you to, funkytown!

请注意bash愉快地让我命名我的函数“[} {”。可能我的代码不够严谨,无法提供实际合法性的确切规则,但它应该说明可能的滥用方式。我希望我能将这个答案标记为“仅限成熟观众”。


1
投票

来自3.3 Shell Functions

Shell函数是一种将命令分组以便以后使用组的单个名称执行的方法。它们像“常规”命令一样执行。当shell函数的名称用作简单命令名时,将执行与该函数名关联的命令列表。 Shell函数在当前shell上下文中执行;没有创建新的流程来解释它们。

使用以下语法声明函数:

name () compound-command [ redirections ]

要么

function name [()] compound-command [ redirections ]

2 Definitions

那么

一个单词,由字母,数字和下划线组成,以字母或下划线开头。名称用作shell变量和函数名称。也称为标识符。


0
投票

此脚本使用1个字符测试函数名称的所有有效字符。


它使用输出53个有效字符(a-zA-Z和下划线) 一个POSIX shell和220个有效字符,BASH v4.4.12。

Ron Burk的答案是有效的,但缺少数字。

#!/bin/sh

FILE='/tmp/FOO'
I=0
VALID=0

while [ $I -lt 256 ]; do {
        NAME="$( printf \\$( printf '%03o' $I ))"
        I=$(( I + 1 ))

        >"$FILE"
        ( eval "$NAME(){ rm $FILE;}; $NAME" 2>/dev/null )

        if [ -f "$FILE" ]; then
                rm "$FILE"
        else
                VALID=$(( VALID + 1 ))
                echo "$VALID/256 - OK: $NAME"   
        fi
} done
© www.soinside.com 2019 - 2024. All rights reserved.