正規表現あり引数を扱ったときに気がついたこと
かなりの小ネタであるが、引数に正規表現を含めて、それをglobを使った時の話である。
glob
globは、ワイルドカードなどの正規表現を展開してくれるもの。下記説明がわかりやすい。
本家はこちら。
内容
Windows上にてコマンドプロンプトでの実行とWSLとの実行で差があったため気が付く(後述するが、理由は単純)
ここでのプログラムは、正規表現にマッチするファイルを表示する単純なものである。
環境
あるティレクトリに下記ファイルが存在、これらをターゲットとする。
$ ls *.txt
f0.txt f1.txt f12.txt f13.txt g1.txt g12.txt h.txt
最初に作成したコード
p1.py
import sys
import glob
# For Windows ' ' is necessary for Linux
all_files = glob.glob(sys.argv[1])
for file in all_files:
print(file)
第1引数をglob()に渡すだけである。
Windowsでの実行(期待どおり)
拡張子txtで、"1"を含むファイルを表示する。
> python p1.py *1*.txt
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
Linuxでの実行(期待どおりでない)
$ python3 p1.py *1*.txt
f1.txt
Linuxでは、シェルで正規表現を展開してしまうため、シェルで最初にマッチしたファイルしか表示されない。そこで、下記のように、シングルクオーテーションにて、正規表現の展開を防ぐと、期待どおりとなった。
$ python3 p1.py '*1*.txt'
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
次に作成したコード(正確にはどこかで見つけたコード)
引数を表示するもの。
q1.py
import sys
# For Linux
args = sys.argv
for i in range(len(args)):
print("args[", i, "] = ", args[i])
Linuxでの実行
$ python3 q1.py *1*.txt
args[ 0 ] = q1.py
args[ 1 ] = f1.txt
args[ 2 ] = f12.txt
args[ 3 ] = f13.txt
args[ 4 ] = g1.txt
args[ 5 ] = g12.txt
シェルで展開された内容が表示される。
Windowsでの実行
> python q1.py *1*.txt
args[ 0 ] = q1.py
args[ 1 ] = *1*.txt
globを用いていないので、当然の結果。
共通化?
引数を表示するプログラムを、WindowsとLinuxで判別したものが下記。
r1.py
import sys
import glob
import platform
os = platform.system()
args = sys.argv
if os == "Linux":
for i in range(1, len(args)):
print(args[i])
elif os == "Windows":
all_files = glob.glob(args[1])
for file in all_files:
print(file)
Windowsでの実行
> python r1.py *1*.txt
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
Linuxでの実行
$ python3 r1.py *1*.txt
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
環境(ここではOS)に合わせて、コードを変える、、、よくある話。
おまけ
今回のトライ&エラーで気がついた「おまけ」も記録。Linuxのシェルスクリプトの話である。
x2.sh, x3.sh
for file in `ls -1 *`
do
echo $file
done
Windows上で作成したコードを、Linux(WSL)で実行した。
$ bash x2.sh
x2.sh: line 5: syntax error: unexpected end of file
コードCR(0x0d)が余計らしい。そこで、下記を実行し、CRを取り除く。
$ tr -d '\r' < x2.sh > x3.sh
$ bash x3.sh
....
x1.py
x2.py
x2.sh
x3.sh
x4.sh
異なる環境では動作しないこともある、、、という教訓。
EOF