web-dev-qa-db-ja.com

BASHでの変数置換とCJK文字の競合

BASHシェルの変数置換で問題が発生しました。
変数aを定義するとします。次に、コマンド

    $> echo ${a//[0-4]/}

0から4までのすべての数値を削除して値を出力します。

    $> a="Hello1265-3World"
    $> echo ${a//[0-4]/}
    Hello65-World

これは問題なく動作するようですが、次の例を見てみましょう。

    $> b="你1265-3好"
    $> echo ${b//[0-4]/}
    你1265-3好

置換は行われませんでした:bにCJK文字が含まれているためだと思います。この問題は、角かっこが関係するすべてのケースに当てはまります。驚くべきことに、角括弧なしの変数置換は、どちらの場合でも正常に機能します。

    $> a="Hello1265-3World"
    $> echo ${a//2/}
    Hello165-3World
    $> b="你1265-3好"
    $> echo ${b//2/}
    你165-3好

それはバグですか、それとも何か不足していますか?

私はLubuntu 12.04を使用していますが、ターミナルはlxterminalおよびecho $BASH_VERSIONは4.2.24(1)-releaseを返します。

EDIT:Andrew Johnson 彼のコメントでは、gnome-terminal 4.2.37(1)-releaseコマンドは正常に機能します。 lxterminalの問題なのか、それとも特定の4.2.24(1)-リリースバージョンの問題なのか、私は思います。

EDIT:私はgnome-terminal Lubuntu 12.04でも問題は解決していません...

6
AndreasT

短い答え:

予想される動作にLC_ALL = Cを設定します

pauhel@permafrost:~$ b="你1265-3好"
paul@permafrost:~$ echo ${b//[0-2]/}
你1265-3好
paul@permafrost:~$ export LC_ALL=C
paul@permafrost:~$ echo ${b//[0-2]/}
你65-3好

長い答え:

期待される動作は、ロケール/ OS実装に依存する照合順序に依存しています。 POSIX標準では、Cロケールを除いて、特に定義されていません。 (Bashはこのために外部ライブラリを呼び出しますが、おそらく、ASCIIのみASCII文字が存在する場合の順序付け)にフォールバックするように見えます)。

それ以降のバージョンのbashには、期待するものを指定できるシェルオプションがあります。

見る:

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

より多くの背景のために。

2
tallus