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

lab*_*nth 24 unix linux syntax bash

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

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

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

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

Tho*_*mas 24

   Shell Function Definitions
       ...
       name () compound-command [redirection]
       function name [()] compound-command [redirection]
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

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

$ bash --version
GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
Run Code Online (Sandbox Code Playgroud)

  • 在 `--posix` 模式下不允许使用连字符(参见第 6.11 节),因此支持连字符是 Bash 主义。我从手册中不确定 Bash 隐式支持哪些其他字符,但我知道 `:` 和 `.` 也可以在函数名称中使用(尽管 `:` 至少会破坏制表符完成)。 (2认同)
  • 如果用关键字“function”定义它们,有时允许使用问号。例如,我有一个函数“source?”,它在采购之前检查是否存在。 (2认同)

ric*_*ici 7

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

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

  • @labyrinth:"echo $ SHELL"不会告诉你哪个shell正在执行.它告诉您当前用户的默认shell是什么.因此,无论出于何种原因,命令很可能在不同的shell中运行(例如,它是在一个脚本中以一个带有`#!/ bin/sh`的shebang行开头).另一种可能性,虽然看起来不太可能,但是脚本是在"posix"shell中运行的,要么是因为设置了环境变量`POSIXLY_CORRECT`,要么是因为执行了`set -p`,或者包含`-p`在`bash`的命令行选项中. (3认同)

Ron*_*urk 6

问题是关于"规则",它已经以两种不同的方式回答,每种方式在某种意义上都是正确的,这取决于你想要称之为"规则"的东西.只是为了充实@罗杰斯国际商品指数的点,你可以推约在功能名称中的任何字符,我写了一个小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
Run Code Online (Sandbox Code Playgroud)

我实际上跳过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!
Run Code Online (Sandbox Code Playgroud)

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

  • 您无法使用全号名称定义函数,但您可以*以数字开头.此外,这里假设的一些非法行为是由于函数调用中的错误引用.例如,你*可以*命名一个函数`*`...但是这个测试的方式,它产生一个错误.因此,函数名称首先不能包含的实际字符列表小于此处的列表...但是第二个字符的列表更长,因为此脚本不再调用该函数正确. (2认同)
  • 你_可以_使用`function * { echo hello; }`(在 Bash 4.4 中),但您可能需要在调用它时将其转义以避免通配。`~`(波浪号扩展)和 `!`(否定退出代码)也是如此。`?` 和 `*` 一样,如果你有单字符的文件名。你也可以定义一个函数 `%`,但我找不到调用它的方法,因为只给出一个以 `%` 开头的词与在它上面运行 `fg` 的作用相同,即使被转义。如果禁用`interactive_comments`,则只能在_interactive_ shell 中使用`#` 作为函数名(非交互式shell 总是将`#` 作为注释标记)。 (2认同)