globのパス名に[^]を指定すると誤作動

カレントディレクトリに以下のようなファイルがあるとする。

$ ls
_sample1.txt  _sample3.txt  sample2.txt
_sample2.txt  sample1.txt   sample3.txt


ファイル名の先頭が「_」でないファイルだけを表示すると、

$ ls [^_]*.txt
sample1.txt  sample2.txt  sample3.txt

irbで実験

Rubyの対話スクリプトirbでDir.globを使って同じことをやってみます。

$ irb --prompt simple
>> Dir.glob('[^_]*.txt')
=> ["sample2.txt", "sample3.txt", "sample1.txt"]

シェルでの結果と同じです。
なお、Dir.globで得られる配列の格納順序は不定なため、ファイル名がソートされていません。

Pythonで実験

対話モードのpythonで同じことをやってみます。

>>> import glob
>>> glob.glob('[^_]*.txt')
['_sample2.txt', '_sample3.txt', '_sample1.txt']

『先頭が「_」で始まらない』ファイルを指定しているはずなんですが、どういうわけか、「_」で始まるファイルだけが表示されてしまいました。

いったい、どうしたことでしょうか。

解決策

^の代わりに!を使えばいいようです。

[^a-c]*.txt → [!a-c]*.txt

元々、Bシェルでは!を使っていたのが、CシェルやBashでは^も使えるようになったというのが真相のようです。

Pythonプログラミング物語 © 2016 Frontier Theme