我想在我的 POSIX shell 脚本注释中包含几个非 ASCII 字符。请注意,这绝不是“posix 支持哪些字符编码?”的重复,因为我只关心注释部分。因此,我不在乎是否可以使用 Unicode 进行实际编码。我关心的是所有兼容 POSIX 的 shell 是否都能读取我的文件,或者某些 shell 是否会因非 ASCII 编码而失败。
因此,我的编辑器(VS Code)将使用 UTF-8 编码保存这样的文件。
以下是该实用程序识别的两个文件file
(不确定它是否关心 BOM):
$ file script1*
script1: POSIX shell script, ASCII text executable
script1.utf: POSIX shell script, Unicode text, UTF-8 text executable
问题是,POSIX shell 脚本是否必须仅使用 ASCII。找不到与此主题相关的任何内容。谢谢。
POSIX 指定了如何识别标记,包括注释:
您具体询问的是 UTF-8;UTF-8 确保换行符按 ASCII 编码,并且只有换行符会产生相应的字节值。因此,任何非 ASCII UTF-8 字符编码都不会被误认为换行符,这意味着 UTF-8 可以安全地用于符合 POSIX 标准的 shell 中的注释。
您的问题顺便提到了 BOM; UTF-8 中不需要BOM ,并且以 BOM 开头的文件不向后兼容 ASCII。以 BOM 开头的 shell 脚本不符合 POSIX 标准,并且不会按预期运行:
BOM 被视为第一个标记的一部分,因此 shell 会查找与“BOM
echo
”匹配的命令,但找不到。接受的答案很好,但让我用稍微不同的角度来解释一下:
POSIX 在处理字符编码方面非常精确和完整。也就是说,相关页面中提到了非平凡字符编码的任何可能影响。如本答案所示,它基本上对存在哪些字符提出了最低要求,但并没有对这些字符的编码做出任何真正的限制。它确实定义了在某些困难情况下会发生什么(例如,在某些情况下无效编码;特殊 NUL 字节的出现;要求字符集中包含一定数量的最小字符等等)。标准的相关部分是POSIX 字符集。
请注意,在绝大多数地方,POSIX 谈论的是字符,而不是字节。事实上,如果你在POSIX Shell 命令语言中查找“字节” ,任何提到“字节”的地方总是在编码可能出错的地方,或者涉及 RAM 限制(即最大路径长度)等等,或者在用户通过在 shell 中设置相关环境变量来更改编码时应该发生什么的情况下。在所有“正常”描述(即 shell 命令)中,它只谈论字符。
具体来说,注释字符定义如下:
在上面链接的字符集规范中,我们发现:
(
#
或<number-sign>
属于可移植字符集的一部分)。后者很有趣。您问的 UTF-8 包含 7 位 ASCII 作为字符定义和编码的真正子集,因此假设得到满足。在这种情况下,UTF-16 会很困难,因此(出于许多其他原因)UTF-16 不符合 POSIX标准。
对于您当前的问题:注释之后,所有格式正确的 UTF-8 用法都是可以的。注释(数字符号)和换行符在 UTF-8 中定义完全明确且安全;并非巧合的是,UTF-8 还确保编码为多个字节的字符本身不包含 7 位 ASCII 字节,因此在随机 UTF-8 编码中不会出现非自愿的数字符号或换行符。
所有不易指定的内容都被 POSIX 明确指定为“未指定”。因此,如果您的脚本包含无效编码,会发生什么情况呢?嗯,未定义。例如,如果在注释末尾,在换行符之前,最后一个字符应该是多字节编码,而换行符位于中间 -> 未指定。预计会出现错误和各种滑稽的情况。
也就是说,一个行为良好的命令要么不(需要)关心这种情况,基本上将所有内容视为字节,只关心特定的 7 位字节(即控制字符)。
或者,如果命令确实支持 UTF-8,则应应用通常的 UTF-8 定义的恢复方法来检测和处理无效编码。具体来说,根据RFC 3629 - UTF-8:
但是,就这个问题而言,POSIX 对此只字未提。
如果您担心真正符合 POSIX 标准的 shell,上述答案没问题。但 Real World™ 不符合 POSIX 标准。您会遇到能够顺利处理 Latin-1、UTF-8 或其他奇特编码的 shell。并且(最有可能出现在较旧、功能有限或仅部分类似 Unix 的系统中)您还会发现,如果输入不是严格的 ASCII,它们会很合适。
Postel 的原则是:“发送时要保守,接受时要宽容”。在这里,您是发送者。