296

Is there a Python method to create directories recursively? I have this path:

/home/dail/

I would like to create

/home/dail/first/second/third

Can I do it recursively or I have to create one directory after the other?

The same thing for:

chmod and chown can I do it recursively without assign permissions for each file/dir?

4

5 Answers 5

452

starting from python 3.2 you can do this:

import os
path = '/home/dail/first/second/third'
os.makedirs(path, exist_ok=True)

thanks to the exist_ok flag this will not even complain if the directory exists (depending on your needs....).


starting from python 3.4 (which includes the pathlib module) you can do this:

from pathlib import Path
path = Path('/home/dail/first/second/third')
path.mkdir(parents=True)

starting from python 3.5 mkdir also has an exist_ok flag - setting it to True will raise no exception if the directory exists:

path.mkdir(parents=True, exist_ok=True)
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for help. I always was using os.mkdir which didn't make grandchildren and more nested children. os.makedirs just solved my problem
@Hamed_gibago you do not even need to use the pathlib module. os.makedirs is recursive itself...
Nice one. pathlib works for me.
259

os.makedirs is what you need. For chmod or chown you'll have to use os.walk and use it on every file/dir yourself.

3 Comments

Specifically: os.makedirs(os.path.join("/home/dail", "first", "second", "third"))
note, exist_ok=True is convenient to save having to check if it exists first every time.
Note that the exist_ok parameter was only added in Python 3.2
15

Try using os.makedirs:

import os
import errno

try:
    os.makedirs(<path>)
except OSError as e:
    if errno.EEXIST != e.errno:
        raise

2 Comments

Welcome to Stack Overflow! Thank you for this code snippet, which may provide some immediate help. A proper explanation would greatly improve its educational value by showing why this is a good solution to the problem, and would make it more useful to future readers with similar, but not identical, questions. Please edit your answer to add explanation, and give an indication of what limitations and assumptions apply.
I would say this answer is the correct one for Python 2.x, since it handles errors correctly and doesn't asks for file system for path twice (as with os.path.exists approach).
8

Here is my implementation for your reference:

def _mkdir_recursive(self, path):
    sub_path = os.path.dirname(path)
    if not os.path.exists(sub_path):
        self._mkdir_recursive(sub_path)
    if not os.path.exists(path):
        os.mkdir(path)

Hope this help!

2 Comments

If the first folder doesn't exist this function will result in stack overflow (if not os.path.exists(sub_path) will always be true and call itself). But as long as the first dir exist this seems to be working.
Simply resolved by first checking if the first folder exists.
8

I agree with Cat Plus Plus's answer. However, if you know this will only be used on Unix-like OSes, you can use external calls to the shell commands mkdir, chmod, and chown. Make sure to pass extra flags to recursively affect directories:

>>> import subprocess
>>> subprocess.check_output(['mkdir', '-p', 'first/second/third']) 
# Equivalent to running 'mkdir -p first/second/third' in a shell (which creates
# parent directories if they do not yet exist).

>>> subprocess.check_output(['chown', '-R', 'dail:users', 'first'])
# Recursively change owner to 'dail' and group to 'users' for 'first' and all of
# its subdirectories.

>>> subprocess.check_output(['chmod', '-R', 'g+w', 'first'])
# Add group write permissions to 'first' and all of its subdirectories.

EDIT I originally used commands, which was a bad choice since it is deprecated and vulnerable to injection attacks. (For example, if a user gave input to create a directory called first/;rm -rf --no-preserve-root /;, one could potentially delete all directories).

EDIT 2 If you are using Python less than 2.7, use check_call instead of check_output. See the subprocess documentation for details.

7 Comments

But that's not Python, it's a shell script! If you can write a solution in Python that's pretty simple, and even portable, do it that way. ;)
@Rosh: I agree 100% that its python calling the *nix shell commands and isn't portable (and said so). But I often find myself writing quick python scripts that I'll only use on my own linux boxes. Calling shell commands may be simpler for those purposes, when you can accomplish what you want with a flag (e.g., -R rather than a walk double-for loop--(second loop for files in each walked dir)). Sure I could have written them in bash, but I feel python's syntax is convenient (easily defining functions/classes) and having access to all the command line flags is convenient for me.
@dothebart I agree forking is often a bad idea and will have more overhead. But the difference is a couple milliseconds (so unless you are creating thousands of directories or on a very resource strapped system -- and then you may want to reconsider python). Sometimes a familiar shell command that does exactly what you want in one line is more convenient than replicating the functionality in python using python's commands that come with less built-in (e.g., python's os.chmod and os.chown not having recursive options). Saying forking is always bad seems like a premature optimization.
have a look at the pyrrd module and rethink. The solution now lifted up deserves more attention - thats wy I voted it up, and this down.
I fail to see the significance of pyrrd (a convenience wrapper around a round robin db tool and existing python bindings) to this discussion. According to its pypi page, half of that module is just an object oriented interface to calling a binary with Popen (that is "forking" which you said "is always a bad idea"). (Now, with PyRRD, there are two additional ways to use RRDTool from Python: an object-oriented interface that wraps system calls (Popen) to the rrdtool binary).
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.