为什么 bash 扩展全局变量替换在字节级别起作用?

Pet*_*r.O 7 bash wildcards locale variable-substitution

我认为 bash 变量替换和通配符在字符分辨率下工作,所以我很惊讶地看到它在字节级别起作用。
我的一切locale都是 en_AU.UTF-8

当没有匹配项并且模式允许零对多时,替换发生在字节级别,如后续替换所见。我原以为它会移动到下一个字符,但它没有......

也许这只是一个奇怪的边缘案例模式,或者我遗漏了一些明显的东西,但我确实想知道这里发生了什么,除了这种特殊模式之外,我还能期待这种行为吗?

这是脚本(它开始尝试将字符串拆分为字符)。
我希望最后一个带有 character 的测试?最终只会在之前有一个空格?,但相反,该字符的 3 个 UTF-8 字节每个都前面有一个空格。这会导致无效的 UTF-8 输出。

shopt -s extglob
for str in  $'\t' "ab"  ? ;do
    printf -- '%s' "${str//*($'\x01')/ }" |xxd
done
Run Code Online (Sandbox Code Playgroud)

输出:

0000000: 2009                                      .
0000000: 2061 2062                                 a b
0000000: 20e0 20a4 20b3                            . . .
Run Code Online (Sandbox Code Playgroud)

Jam*_*man 4

您的问题的简短答案是 *(pattern-list) 将匹配给定模式的零次或多次出现。每个输入字节之间有零个 Unicode 字符 0001 实例。因此,替换操作将这零个实例中的每一个替换为一个空格。

\n\n

也许你想这样做:

\n\n
$ for str in  $\'\\t\' "ab"  \xe0\xa4\xb3 ; do  \n    printf -- \'%s\' "${str//+($\'\\x01\')/ }" |xxd\n  done)\n0000000: 09                                       .\n0000000: 6162                                     ab\n0000000: e0a4 b3                                  ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

但更长的答案是,无论如何,路径名都不是文本。至少,就(类 Unix)操作系统而言,它们还不够。它们是字节序列。问题是这样的事情做起来很简单:

\n\n
$ LC_ALL=latin1\n$ mkdir \'\xc3\xa1\xc3\xb1\' && cd \'\xc3\xa1\xc3\xb1\'\n$ LC_ALL=ga_IE.iso885915@euro\n$ mkdir \'\xe2\x82\xac25\' && cd \'\xe2\x82\xac25\'\n$ LC_ALL=zh_TW\n$ pwd\n# ... what should the output be?  And what about the output of:\n$ /bin/pwd\n
Run Code Online (Sandbox Code Playgroud)\n\n

每个语言环境都包含其他语言环境中不存在的字符。这个问题也会影响像locate -rfind -regex这样的东西;locate -r的参数是一个正则表达式,因此必须包含对字符类等内容的支持;但您不知道使用什么区域设置来确定路径名中字符的字符类,或者即使有一个可用的区域设置可用于表示系统上的所有路径。

\n