Pythonのglobの使い方。再帰的にファイルのパスを取得する便利ライブラリ
- 作成日: 2021-01-24
- 更新日: 2024-01-06
- カテゴリ: Python
Pythonのglobの使い方
Pythonにはパスを収集するライブラリ「glob(グロブ)」があります。
このglob
を使うとファイルシステム上から簡単にファイルのパスを収集することが出来ます。
パターンによるマッチを行うので直観的にパスを収集可能です。
この記事ではglob
を賢く使う方法を解説します。
globのインポート
glob
はglob
モジュールに定義されています。
ですので使用する場合はglob
をインポートします。
import glob
# glob.glob(...) で使える
# あるいは
from glob import glob
# glob(...)で使える
globの構造
glob()
の構造は以下のようになっています。
glob.glob(
pathname, # パス
*,
root_dir=None, # 検索のルートフォルダ(ルートディレクトリ)
dir_fd=None, # ディレクトリ記述子への相対パス
recursive=False, # 真の場合、パターン「**」が再帰的にマッチ
include_hidden=False # 真の場合、パターン「**」は隠しフォルダにマッチ
)
バージョン3.5から**
の再帰的なマッチがサポートされています。
またバージョン3.10からroot_dir
とdir_fd
の引数のサポート。
バージョン3.11からinclude_hidden
引数がサポートされました。
返り値はpathname
にマッチしたパス名のリストになります。
glob()
はpathname
にマッチするパス名のリストを返しますが、この返り値は空になることもあります。
pathname
は/mnt/d/src/folder/Makefile
のような絶対パス、それから../../folder/*/*.png
のような相対パスも使えます。
シェルでよく使われるワイルドカード(*
)も使うことが出来ます。
参照先がない、壊れているシンボリックリンクも結果のリストには含まれますので、参照する場合は参照先があるか注意する必要があります。
返り値の結果がソートされているかどうかはファイルシステムによります。
glob()
の実行中に参照中のファイルやフォルダが削除されたり追加されたりした場合は、それらのパス名が返り値に含まれるかどうかは不定になっています。つまり含まれるかもしれないし、含まれないかもしれません。
glob()のpathnameに指定できる展開記法
glob()
の第1引数に指定するパターンはシェル由来のワイルドカードを指定できます。
ワイルドカード | 一致対象 | |
? | 任意の一文字 | |
* | 任意の文字列 | |
[set] | set の中のいずれかの文字 | |
[!set] | set の中のいずれでもない文字 |
(参考: 1. bash の基礎)
任意の1文字
?
を使うと、任意の1文字にマッチさせることができます。
たとえば↓のパターンは
file.?
↓のファイルにマッチします。
file.c file.h file.o
任意の文字列
*
を使うと任意の文字列にマッチさせることができます。
たとえば↓のパターンは
my-*.txt
↓のファイルにマッチします。
my-cat.txt my-dog.txt my-bird.txt
setの中のいずれかの文字
[set]
を使うと[]
で囲まれたいずれかの文字にマッチさせることができます。
たとえば↓のパターンは
file-[ab].txt
↓のファイルにマッチします。
file-a.txt file-b.txt
setの中のいずれでもない文字
[!set]
を使うと[!]
の中のいずれでもない文字にマッチさせることができます。
たとえば↓のパターンは
file-[!ab].txt
↓のファイルなどにマッチします。
file-x.txt file-y.txt
解説に使うディレクトリ構造
今回は↓のようなディレクトリとファイルを解説に使います。
$ tree animals/
animals/
├── cat
│ ├── mikeneko.jpg
│ └── mikeneko.png
└── dog
├── chiwawa.jpg
└── chiwawa.png
2 directories, 4 files
globでディレクトリを得る
glob()
でディレクトリを取得するには↓のようにディレクトリ名を指定します。
import glob
files = glob.glob('animals')
print(files)
# ['animals']
しかしパスをベタ書きするのであれば、そのパスを使えばいいので↑のようなコードはあまりglob
の利点が目立っていません。
globで複数のファイルを集める
glob()
で複数のファイルを集める場合は↓のようにワイルドカードを使います。
import glob
files = glob.glob('animals/*')
print(files)
# ['animals/cat', 'animals/dog']
↑の出力結果を見ると、animals/
直下のディレクトリが収集できているのがわかります。
再帰的には収集していない点に注意が必要です。
再帰的に収集したい場合は後述の「globで再帰的にすべてのファイルを集める」をご覧ください。
また、特定の拡張子のファイルを収集したい場合は↓のようにします。
import glob
files = glob.glob('animals/cat/*.png')
print(files)
# ['animals/cat/mikeneko.png']
root_dir: globでルートフォルダを指定して検索する
root_dir
に検索のルートフォルダ(ルートディレクトリ)を指定すると、そのフォルダを起点にして検索できます。
下記の例ではroot_dir
をanimals
にして*
でフォルダ内のフォルダを取得しています。
import glob
files = glob.glob('*', root_dir='animals')
print(files)
# ['cat', 'dog']
dir_fd: globで開いたフォルダのディスクリプタを指定する
glob()
のdir_fd
にはファイルディスクリプタを指定できます。
ディスクリプタとは低水準ファイルI/Oのファイルを表す整数のことを言います。
このディスクリプタはos.open()
で取得できます。
os.O_RDONLY
で読み込み専用のフラグを指定してフォルダを開きます。
フォルダ? ファイルじゃないの? と思われるかもしれませんがフォルダはファイルの一種です。
import glob
import os
# フォルダのディスクリプタを取得
dir_fd = os.open('/tmp/animals', os.O_RDONLY)
# ディスクリプタを指定してマッチさせる
files = glob.glob('*', dir_fd=dir_fd)
print(files)
# ['cat', 'dog']
# ディスクリプタを閉じる
os.close(dir_fd)
注意点としてはディスクリプタは開いたらos.close()
で閉じる必要があるということです。
ファイルとトイレのドアは開いたら閉じときましょう。
recursive: globで再帰的にすべてのファイルを集める
パターンに**
を指定し、recursive
をTrue
にするとglob()
はパスを再帰的に収集します。
import glob
files = glob.glob('**', recursive=True)
print(files)
# ['animals', 'animals/cat', 'animals/cat/mikeneko.jpg', 'animals/cat/mikeneko.png', 'animals/dog', 'animals/dog/chiwawa.jpg', 'animals/dog/chiwawa.png', 'sample.py']
sample.py
は↑のスクリプトです。
↑の出力を見るとanimals/
ディレクトリを再帰的に下って行ってファイルのパスを取得しているのがわかります。
include_hidden: globで隠しフォルダにマッチさせる
glob
のinclude_hidden
をTrue
にすると隠しファイルも取得できるようになります。
Linuxでは隠しファイルはドット(.
)で始まるファイル名のファイルです。
このinclude_hidden
はバージョン3.11から使えます。
$ # 隠しファイルの作成(LinuxのBashで)
$ touch animals/.hidden
import glob
files = glob.glob('animals/*', include_hidden=True)
print(files)
# ['animals/.hidden', 'animals/cat', 'animals/dog']
globの実装
Pythonではglob
はglob.py
に実装されています。
glob()
内部ではiglob()
の結果をlist()
に変換して返しています。
つまりglob()
の動作のほとんどはiglob()
によるものです。
さらにiglob()
の内部では_iglob()
や_glob1
や_glob2
なども呼ばれています。
cpython/Lib/glob.py at main · python/cpython · GitHub
おわりに
今回はPythonのライブラリglob
の使い方を解説しました。
glob
はPythonのパワーを感じられる良いライブラリだと思います。
特定のディレクトリ以下のパスをまとめて取得したい時に威力を発揮するライブラリです。
関連記事
Djangoでオブジェクトを一括作成・更新【bulk_create, bulk_update】
DjangoのModel.objects.filter()の使い方【QuerySet】
Djangoのmodelのcreate()の使い方【Python】
Django入門: ルートの設定 ~ 簡単な一行掲示板アプリを作る その4【Windows10】
NumPyのappend()の使い方: 配列の末尾に要素を追加
Numpyのarangeの使い方: 指定範囲の数列を生成する
Python3でYoutube Data APIを使ってキーワード検索する
PythonからC言語(my.puts)を呼び出して実行する