Bash Globbingは期待どおりではありません


8

これ宿題です:

小文字で始まり、大文字で終わらない2文字以上のすべてのファイル名を照合します。

私のソリューションが機能しない理由がわかりません。

だから私は以下を実行しました:

touch aa
touch ha
touch ah
touch hh
touch a123e
touch hX
touch Ax

ls [a-z]*[!A-Z]

出力:

aa  ha

私の質問:「ah」、「hh」、または「a123e」と一致しなかったのはなぜですか?


下に適切に私の作品mkshのシェルではなくbash --posix、そうそこのお奨めは、bash`のためのいくつかの特定の規則も
Sergiy Kolodyazhnyy

@Serg、[AZ]の動作は、Cロケールを除いてPOSIXで指定されていないことに注意してください。mksh以下のようなzshのは、[A-Z]上の一致していませんÉ例えば。ksh93はに[A-Z]一致しますÉが、には一致しませんh
ステファンChazelas

回答:


9

これはロケールの問題です。あなたのロケールで[A-Z]は、のような[AbBcZ...zZ](おそらくアクセント付き文字のような他の)に展開されます。したがって、[^A-Z]実際にはaあなたの例では(そしてあなたの例だけで)「で終わるファイル」を意味します。

そのような驚きを避けたい場合は、1つの方法を設定することです。LC_COLLATE=C これは、照合順序がロケール設定の一部であり、並べ替え順序を制御するためです。また、LC_ALL優先されるため、設定されている場合は空です。

$ ls [a-z]*[^A-Z]
aa  ha

$ ( LC_ALL=; LC_COLLATE=C; ls [a-z]*[^A-Z] )
a123e  aa  ah  ha  hh

または、より良い、それはあなたのロケール設定を変更し、適切なクラスを使用しないように、おそらく望ましいです:[:lower:]代わりに[a-z][:upper:]の代わりに[A-Z]

$ ls [[:lower:]]*[^[:upper:]]
a123e  aa  ah  ha  hh

または、bashのglobasciirangesオプションを使用します。

$ shopt -s globasciiranges
$ ls [a-z]*[^A-Z]
a123e  aa  ah  ha  hh

$ shopt -u globasciiranges
$ ls [a-z]*[^A-Z]
aa  ha

@ heemayl、no LC_ALL=C ls [a-z]*[^A-Z]lsシェルのロケールにのみ影響し、シェルがグロブを展開したりコマンドラインを解析したりするロケールには影響しません。
ステファンChazelas

LC_xxxグロブに適用するためにエクスポートする必要はありませんが、lsが同じロケールを取得できるようにすることをお勧めします。
ステファンChazelas

1
文字セットは、例えばGB18030ロケールでは、LC_ALL = Cのアプローチと、それが呼ばれるファイルに一致しないことに注意してくださいtest-鏏あなたはCロケールのものに文字セットを変更するとため、インスタンスのために、なり<0xe7>A。IOW、LC_CTYPEを変更すると、別の文字が表示されます。
ステファンChazelas

1
OPのロケールの[AZ]はAbBcC ... zZよりも多くカバーしていると思います。これはおそらくもありéÁ(おそらくありませんŹ)。IOW、[A-Z]Cロケール以外ではほとんど意味がありません。
ステファンChazelas

@StéphaneChazelas素晴らしいフィードバックをありがとうございます。回答を更新しました。私はすべてを考慮したと思います。
xhienne
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.