BASH中变量替换和CJK字符之间的冲突

And*_*asT 7 bash lubuntu utf-8 lxterminal

我在 BASH shell 中遇到了变量替换的问题。
假设您定义了一个变量a。然后命令

    $> echo ${a//[0-4]/}
Run Code Online (Sandbox Code Playgroud)

打印其值,并删除所有介于 0 和 4 之间的数字:

    $> a="Hello1265-3World"
    $> echo ${a//[0-4]/}
    Hello65-World
Run Code Online (Sandbox Code Playgroud)

这似乎工作得很好,但让我们看看下一个例子:

    $> b="?1265-3?"
    $> echo ${b//[0-4]/}
    ?1265-3?
Run Code Online (Sandbox Code Playgroud)

没有发生替换:我认为这是因为b包含 CJK 字符。这个问题扩展到所有涉及方括号的情况。令人惊讶的是,没有方括号的变量替换在两种情况下都可以正常工作:

    $> a="Hello1265-3World"
    $> echo ${a//2/}
    Hello165-3World
    $> b="?1265-3?"
    $> echo ${b//2/}
    ?165-3?
Run Code Online (Sandbox Code Playgroud)

这是一个错误还是我错过了什么?

我使用 Lubuntu 12.04,终端是lxterminalecho $BASH_VERSION返回 4.2.24(1)-release。

编辑: 安德鲁约翰逊在他的评论中表示,使用gnome-terminal4.2.37(1)-release 命令可以正常工作。我想知道这是否是lxterminal其特定的 4.2.24(1)-release 版本的问题。

编辑:gnome-terminal在 Lubuntu 12.04 上尝试过,但问题仍然存在......

小智 3

简短回答:

\n\n

设置 LC_ALL=C 以获得您期望的行为

\n\n
pauhel@permafrost:~$ b="\xe4\xbd\xa01265-3\xe5\xa5\xbd"\npaul@permafrost:~$ echo ${b//[0-2]/}\n\xe4\xbd\xa01265-3\xe5\xa5\xbd\npaul@permafrost:~$ export LC_ALL=C\npaul@permafrost:~$ echo ${b//[0-2]/}\n\xe4\xbd\xa065-3\xe5\xa5\xbd\n
Run Code Online (Sandbox Code Playgroud)\n\n

长答案:

\n\n

您期望的行为依赖于排序规则,而排序规则取决于语言环境/操作系统实现。除 C 语言环境外,POSIX 标准未明确定义它。(Bash 为此调用一个外部库,据猜测,如果仅存在 ASCII 字符,则看起来会回退到 ASCII 排序)。

\n\n

bash 的更高版本有一个 shell 选项,可以让您指定您期望的内容。

\n\n

看:

\n\n

https://groups.google.com/forum/#!topic/gnu.bash.bug/S6cN9KI4vK4/discussion

\n\n

了解更多背景。

\n