Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

¿Existe una manera de obtener una funcionalidad similar a mkdir -p en el shell desde Python? Estoy buscando una solución que no sea una llamada al sistema. Estoy seguro de que el código tiene menos de 20 líneas y me pregunto si alguien ya lo ha escrito.

¿Fue útil?

Solución

mkdir -p funcionalidad de la siguiente manera:

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
        else:
            raise

Actualizar

Para Python = 3.2, os.makedirs tiene un tercer argumento opcional exist_ok que, cuando es verdadero, habilita la funcionalidad mkdir -p - a menos que < se proporciona code> mode y el directorio existente tiene permisos diferentes a los previstos; en ese caso, OSError se genera como anteriormente.

Actualización 2

Para Python = 3.5, también hay pathlib .Path.mkdir :

import pathlib

pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)

El parámetro exist_ok se agregó en Python 3.5.

Otros consejos

En Python > = 3.2, eso es

os.makedirs(path, exist_ok=True)

En versiones anteriores, use la respuesta de @ tzot .

Esto es más fácil que atrapar la excepción:

import os
if not os.path.exists(...):
    os.makedirs(...)

Descargo de responsabilidad Este enfoque requiere dos llamadas al sistema que son más susceptibles a las condiciones de carrera en ciertos entornos / condiciones. Si está escribiendo algo más sofisticado que un simple script desechable que se ejecuta en un entorno controlado, es mejor que vaya con la respuesta aceptada que solo requiere una llamada al sistema.

ACTUALIZACIÓN 2012-07-27

Estoy tentado de eliminar esta respuesta, pero creo que hay valor en el hilo de comentarios a continuación. Como tal, lo estoy convirtiendo a un wiki.

Recientemente, encontré este distutils.dir_util.mkpath :

In [17]: from distutils.dir_util import mkpath

In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']

mkdir -p le da un error si el archivo ya existe:

$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists

Por lo tanto, un refinamiento de las sugerencias anteriores sería volver a generar la excepción si os.path.isdir devuelve False (al verificar para errno.EEXIST ).

(Actualizar) Consulte también esto pregunta muy similar ; Estoy de acuerdo con la respuesta aceptada (y advertencias), excepto que recomendaría os.path.isdir en lugar de os.path.exists .

(Actualización) Por una sugerencia en los comentarios, la función completa sería:

import os
def mkdirp(directory):
    if not os.path.isdir(directory):
        os.makedirs(directory) 

Como se mencionó en las otras soluciones, queremos poder acceder al sistema de archivos una vez mientras imitamos el comportamiento de mkdir -p . No creo que esto sea posible, pero deberíamos acercarnos lo más posible.

Primero el código, luego la explicación:

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

Como los comentarios a la respuesta de @tzot indican que hay problemas para verificar si puede crear un directorio antes de que realmente lo cree: no puede decir si alguien ha cambiado el sistema de archivos mientras tanto. Eso también encaja con el estilo de Python de pedir perdón, no permiso.

Entonces, lo primero que debemos hacer es tratar de hacer el directorio, luego, si sale mal, averiguar por qué.

Como señala Jacob Gabrielson, uno de los casos que debemos buscar es el caso en que ya existe un archivo en el que estamos tratando de colocar el directorio.

Con mkdir -p :

$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists

El comportamiento análogo en Python sería generar una excepción.

Así que tenemos que resolver si este fue el caso. Desafortunadamente, no podemos. Recibimos el mismo mensaje de error de makedirs si existe un directorio (bueno) o existe un archivo que impide la creación del directorio (malo).

La única forma de resolver lo que sucedió es inspeccionar el sistema de archivos nuevamente para ver si hay un directorio allí. Si lo hay, devuélvalo en silencio, de lo contrario, genere la excepción.

El único problema es que el sistema de archivos puede estar en un estado diferente ahora que cuando se llamó a makedirs. por ejemplo: existía un archivo que causaba fallos en makedirs, pero ahora hay un directorio en su lugar. Eso realmente no importa mucho, porque la función solo se cerrará en silencio sin generar una excepción cuando en el momento de la última llamada al sistema de archivos existía el directorio.

Con Pathlib de la biblioteca estándar de python3:

Path(mypath).mkdir(parents=True, exist_ok=True)
  

Si los padres son verdaderos, los padres que faltan en este camino se crean como   necesario; Se crean con los permisos predeterminados sin tomar   modo en cuenta (imitando el comando POSIX mkdir -p).   Si exist_ok es falso (el valor predeterminado), se genera un FileExistsError si   el directorio de destino ya existe.

     

Si exist_ok es verdadero, las excepciones FileExistsError serán ignoradas (igual   como el comando POSIX mkdir -p), pero solo si la última ruta   El componente no es un archivo que no sea de directorio.

     

Cambiado en la versión 3.5: se agregó el parámetro exist_ok.

Creo que la respuesta de Asa es esencialmente correcta, pero puedes extenderla un poco para que actúe más como mkdir -p , ya sea:

import os

def mkdir_path(path):
    if not os.access(path, os.F_OK):
        os.mkdirs(path)

o

import os
import errno

def mkdir_path(path):
    try:
        os.mkdirs(path)
    except os.error, e:
        if e.errno != errno.EEXIST:
            raise

Ambos manejan el caso donde la ruta ya existe de manera silenciosa, pero permiten que otros errores se disparen.

Declaración de función;

import os
def mkdir_p(filename):

    try:
        folder=os.path.dirname(filename)  
        if not os.path.exists(folder):  
            os.makedirs(folder)
        return True
    except:
        return False

uso:

filename = "./download/80c16ee665c8/upload/backup/mysql/2014-12-22/adclient_sql_2014-12-22-13-38.sql.gz"

if (mkdir_p(filename):
    print "Created dir :%s" % (os.path.dirname(filename))

He tenido éxito con lo siguiente personalmente, pero mi función probablemente debería llamarse algo así como 'asegurar que este directorio exista':

def mkdirRecursive(dirpath):
    import os
    if os.path.isdir(dirpath): return

    h,t = os.path.split(dirpath) # head/tail
    if not os.path.isdir(h):
        mkdirRecursive(h)

    os.mkdir(join(h,t))
# end mkdirRecursive
import os
import tempfile

path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)
import os
from os.path import join as join_paths

def mk_dir_recursive(dir_path):

    if os.path.isdir(dir_path):
        return
    h, t = os.path.split(dir_path)  # head/tail
    if not os.path.isdir(h):
        mk_dir_recursive(h)

    new_path = join_paths(h, t)
    if not os.path.isdir(new_path):
        os.mkdir(new_path)

basado en la respuesta de @Dave C pero con un error solucionado donde ya existe parte del árbol

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top