HOWTO · Bash

解决 Bash 中的导出不是有效标识符错误

本文介绍如何解决 Bash 中的 export not a valid identifier 错误。

本页内容

Bash 的 export 命令会在本应是变量名的参数不符合 Bash 标识符规则时报告“不是有效标识符”。常见原因有两种:名称以数字开头,或赋值运算符两侧有空格。请使用以字母或下划线开头的名称,赋值时不要在 = 两侧留空格;值包含空格时则应加引号。导出的标量变量可供子命令使用;Bash 数组不会作为数组通过 export 导出。

“不是有效标识符”错误的含义

Bash 变量标识符必须以 ASCII 字母或下划线开头,后面可以有零个或多个字母、数字或下划线。名称区分大小写,因此 APP_MODE 和 app_mode 是不同的变量。名称的首字符不能是数字,但后续字符可以是数字。标识符中不能包含空格、连字符、句点或其他标点符号。

export 接受变量名,也接受 name=value 形式的赋值。如果赋值内容被空格拆开,Bash 收到的会是多个独立参数,而不是一个赋值。此时它可能把 = 当作传给 export 的参数,并报告该参数不是有效标识符。具体错误信息会因 Bash 拒绝的参数而异。

检查导出语法和标识符

赋值应写成一个 shell 单词,= 两侧都不要留空格:

本节中的代码以及显示的标签或输出仍为英文。

export APP_MODE=production

相比之下,export APP_MODE = production 会被解析为三个参数:APP_MODE、= 和 production。请删除运算符两侧的空格。如果错误命令出现在 ~/.bashrc 或 ~/.bash_profile 等启动文件中,就在文件中修改对应行;除非文件里包含有问题的命令,否则文件本身并不是原因。要快速查找,可以在这些文件中搜索变量名或 export 命令行,然后启动新的 shell,或载入修改后的文件以应用更改。

修正无效的变量名

1st_variable 这类名称以数字开头,因此不能用作 Bash 变量。请将其改为有效标识符,例如 first_variable。下面的独立示例会捕获预期的失败,让 shell 脚本继续执行;随后 export 修正后的名称,并在子 Bash 进程中检查它:

本节中的代码以及显示的标签或输出仍为英文。

if export 1st_variable=hello 2>/dev/null; then
  printf '%s\n' 'Unexpectedly accepted the name'
else
  printf '%s\n' 'The name beginning with a digit was rejected'
fi
export first_variable=hello
bash -c 'printf "%s\n" "$first_variable"'

此示例供读者运行;这里不声称已经执行或观察到任何结果。修正后的标识符符合命名规则,子命令会通过环境接收其 export 后的值。如果需要保留原标签用于显示或查找数据,请将标签存为值,而不要把它用作变量名。

处理包含空格的值

变量名不能包含空格,即使给名称加上引号也不行。引号只会改变 shell 对单词的分组和解释方式,不会改变标识符规则。请在名称中使用下划线;当等号右侧的值包含空格时,为该值加引号,例如 export GREETING="Hello World"。引号会让整个赋值保持为一个整体,而 GREETING 仍是有效标识符。

展开变量值时也要给展开式加引号:printf '%s\n' "$GREETING"。如果值中含有空格或通配符,这样可以避免单词拆分和路径名展开。若 name 存储的是数据,避免使用 export $name=value:把任意文本展开成 shell 语法很脆弱,最终的赋值可能并非你想要的含义。

使用数组,但不要尝试导出数组

Bash 数组可以在当前 Bash 进程中保存多个相关值,但进程环境会将变量表示为字符串。导出数组不会把它的索引结构或关联结构传给子进程。不要依赖 export my_array 来让其他进程获得一个数组。

如果子命令只需要一个值,可以传递或通过 export 导出标量变量。如果需要多个值,请选择子命令能够理解的明确表示方式,例如多个独立的标量环境变量,或有文档说明的分隔符格式,并在子命令中解析该格式。只有在值不会包含该分隔符,或已定义转义规则时,分隔符格式才合适。如果数组只在当前 Bash 脚本中使用,就保留为数组。

验证已导出的变量

在当前 shell 中打印变量只能确认它在此处有值,本身不能证明它已通过 export 导出。请改为从子进程中检查。运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

export APP_MODE=production
bash -c 'printf "%s\n" "$APP_MODE"'

如果变量已通过 export 导出,子命令会打印继承到的值。如果输出为空行,请检查拼写和赋值语法,并确认启动子进程之前,父 shell 中已经运行了 export。

对于启动文件中的命令,请在包含错误赋值的文件里修正它,然后打开新的交互式 shell,或载入该文件。在同一个 shell 中启动子命令来验证结果。这样可以区分名称或解析问题,以及变量只是在另一个 shell 进程中设置的情况。