発生した問題
データセットを作成する時は大体拡張子別にディレクトリを分けているのですが,今回はたまたま 2 種類の拡張子を持つファイルが 1 つのディレクトリに入ってしまっていたので,Python のコード内でこれらを分けて取得する必要がありました.
しかし,この取得の段階で glob コマンドがなぜかうまく動きませんでした.
本記事では発生した事項,解決策,結論について述べたいと思います.
以下に今回のディレクトリ&ファイル構造を示します.
.
├── glob.py
└── dataset_dir
├── 001.txt
├── 002.txt
├── 003.txt
├── ...
├── 100.txt
├── 001.png
├── 002.png
├── 003.png
├── ...
└── 100.png
このディレクトリ構造に対して,以下のコードを用いて.txt
および.png
ファイルの path を格納したリストを作成します.
txt_path = glob.glob(sys.argv[1])
png_path = glob.glob(sys.argv[2])
print(txt_path, len(txt_path))
print(png_path, len(png_path))
python glob.py ./dataset_dir/*.txt ./dataset_dir/*.png
しかし,このプログラムの出力は以下の通りでした.
./dataset_dir/001.png 1
./dataset_dir/002.png 1
なぜこのようなことが発生したのでしょうか?
解決策
私の脳内の理解では以下のようなものでした.
-
python glob.py ./dataset_dir/*.txt ./dataset_dir/*.png
が実行される - プログラム内で与えられた引数が str 変数として
txt_path = glob.glob(./dataset_dir/*.txt)
およびtxt_path = glob.glob(./dataset_dir/*.png)
のように渡される. - glob 関数によってディレクトリ内のファイル一覧を取得する.
しかし,この2が間違っていました.
そもそも,Python の引数としてワイルドカードを利用すると,str としてそのまま受け取られるのではなく,その段階でディレクトリ内全てのファイルを指定したことになるので,実行段階のpython glob.py ./dataset_dir/*.txt ./dataset_dir/*.png
とは,len(sys.argv)
= 3 ではなく,len(sys.argv)
= 101 (script1 + txt50 + png50) という時点でミスを犯していたことになります.
ですので,コマンドライン上でワイルドカードを利用しないというのが正解なようです.
よって,以下のようにプログラムを変更することが正しいです.
txt_path = glob.glob(sys.argv[1] + '/*.txt')
png_path = glob.glob(sys.argv[2] + '/*.png')
print(txt_path, len(txt_path))
print(png_path, len(png_path))
python glob.py ./dataset_dir/
結論
コマンドライン上でワイルドカードを用いると即効魔法が発動するので,sys.argv に吸収される時には既にデータはワイルドに獲得されている.
追記
@yoshi389111 さんよりコメントをいただきました.(2023/01/11 確認)
ご提案いただいた内容は「そもそもコマンドライン上で実行する時にはクォーテーション(またはダブルクォーテーション)で囲うことでワイルドカードを非アクティブ化できる」というものでした.確かに!その手がありました!!
python glob.py './dataset_dir/*.txt' './dataset_dir/*.png'