mkdir -p
Python内からシェルと同様の機能を取得する方法はありますか?システムコール以外の解決策を探しています。コードは20行未満だと思いますが、誰かがすでに書いているのではないかと思います。
12 に答える
Python ≥ 3.5 の場合は、次を使用しますpathlib.Path.mkdir
。
import pathlib
pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)
exist_ok
パラメータは Python 3.5 で追加されました。
Python ≥ 3.2の場合os.makedirs
、オプションの 3 番目の引数exist_ok
がTrue
ありmkdir -p
ます。<em>が指定mode
されていて、既存のディレクトリが意図したものとは異なる権限を持っている場合を除きます。その場合、OSError
以前のように発生します。
import os
os.makedirs("/tmp/path/to/desired/directory", exist_ok=True)
Python のさらに古いバージョンではos.makedirs
、エラーを使用して無視できます。
import errno
import os
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python ≥ 2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
# possibly handle other errno cases here, otherwise finally:
else:
raise
これは、例外をトラップするよりも簡単です。
import os
if not os.path.exists(...):
os.makedirs(...)
免責事項このアプローチでは、特定の環境/条件下での競合状態の影響を受けやすい2つのシステムコールが必要です。制御された環境で実行される単純な使い捨てスクリプトよりも洗練されたものを作成している場合は、1回のシステムコールのみを必要とする受け入れられた回答を使用することをお勧めします。
更新2012-07-27
この答えを削除したくなりますが、以下のコメントスレッドに価値があると思います。そういうものとして、私はそれをウィキに変換しています。
最近、私はこのdistutils.dir_util.mkpathを見つけました:
In [17]: from distutils.dir_util import mkpath
In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
mkdir -p
ファイルが既に存在する場合、エラーが発生します。
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists
したがって、以前の提案を改良するとraise
、例外がos.path.isdir
返された場合False
(をチェックするときerrno.EEXIST
) を再設定することになります。
(更新)この非常によく似た質問も参照してください。os.path.isdir
代わりに推奨することを除いて、受け入れられた回答(および警告)に同意しos.path.exists
ます。
(更新)コメントの提案によると、完全な機能は次のようになります。
import os
def mkdirp(directory):
if not os.path.isdir(directory):
os.makedirs(directory)
python3標準ライブラリの Pathlib を使用:
Path(mypath).mkdir(parents=True, exist_ok=True)
Parents が true の場合、このパスの欠落している親が必要に応じて作成されます。モードを考慮せずにデフォルトのパーミッションで作成されます (POSIX mkdir -p コマンドを模倣します)。exist_ok が false (デフォルト) の場合、ターゲット ディレクトリが既に存在すると FileExistsError が発生します。
exist_ok が true の場合、FileExistsError 例外は無視されます (POSIX mkdir -p コマンドと同じ動作) が、最後のパス コンポーネントが既存の非ディレクトリ ファイルでない場合のみです。
バージョン 3.5 で変更: exist_ok パラメータが追加されました。
他のソリューションで述べたように、mkdir -p
. これができるとは思いませんが、できるだけ近づける必要があります。
最初にコードを書き、後で説明します:
import os
import errno
def mkdir_p(path):
""" 'mkdir -p' in Python """
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
@tzotの回答へのコメントは、実際にディレクトリを作成する前にディレクトリを作成できるかどうかを確認することに問題があることを示しています.その間に誰かがファイルシステムを変更したかどうかはわかりません. これは、許可ではなく許しを求める Python のスタイルにも適合します。
したがって、最初にすべきことはディレクトリを作成することであり、それがうまくいかない場合は、その理由を突き止めます。
Jacob Gabrielson が指摘しているように、探す必要があるケースの 1 つは、ディレクトリを配置しようとしている場所にファイルが既に存在する場合です。
とmkdir -p
:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists
Python での類似の動作は、例外を発生させることです。
したがって、これが事実であったかどうかを解決する必要があります。残念ながら、できません。ディレクトリが存在する (良い) か、ディレクトリの作成を妨げるファイルが存在する (悪い) かに関係なく、makedirs から同じエラー メッセージが返されます。
何が起こったのかを解明する唯一の方法は、ファイル システムをもう一度調べて、そこにディレクトリがあるかどうかを確認することです。ある場合は黙って戻り、そうでない場合は例外を発生させます。
唯一の問題は、ファイル システムが makedirs が呼び出されたときとは異なる状態になっている可能性があることです。例: makedirs が失敗する原因となったファイルが存在していましたが、現在はディレクトリがその場所にあります。最後のファイルシステム呼び出し時にディレクトリが存在していた場合、関数は例外を発生させずにサイレントに終了するだけなので、それはそれほど重要ではありません。
Asa の答えは本質的に正しいと思いますが、少し拡張して のように振る舞うことができmkdir -p
ます。
import os
def mkdir_path(path):
if not os.access(path, os.F_OK):
os.mkdirs(path)
また
import os
import errno
def mkdir_path(path):
try:
os.mkdirs(path)
except os.error, e:
if e.errno != errno.EEXIST:
raise
これらは両方とも、パスがすでに存在する場合を黙って処理しますが、他のエラーが発生するのを許します。
import os
import tempfile
path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)