263

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?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Dail
  • 2,639
  • 2
  • 15
  • 3

5 Answers5

390

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)
hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
256

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.

Jason S
  • 184,598
  • 164
  • 608
  • 970
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
15

Try using os.makedirs:

import os
import errno

try:
    os.makedirs(<path>)
except OSError as e:
    if errno.EEXIST != e.errno:
        raise
wonder.mice
  • 7,227
  • 3
  • 36
  • 39
YOUYANG
  • 171
  • 1
  • 3
  • 4
    Welcome to Stack Overflow! Thank you for this code snippet, which may provide some immediate help. A proper explanation [would greatly improve](//meta.stackexchange.com/q/114762) 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. – Toby Speight Jun 01 '17 at 12:13
  • 1
    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). – wonder.mice Mar 19 '18 at 22:22
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!

Mars
  • 179
  • 2
  • 1
  • 4
    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. – Ronen Ness Dec 19 '16 at 08:34
  • 1
    Simply resolved by first checking if the first folder exists. –  Mar 24 '22 at 18:07
7

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.

ndmeiri
  • 4,979
  • 12
  • 37
  • 45
dr jimbob
  • 17,259
  • 7
  • 59
  • 81
  • 4
    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 Oxymoron May 14 '11 at 19:16
  • 1
    @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 `walk`ed 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. – dr jimbob May 14 '11 at 19:35
  • @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. – dr jimbob Aug 06 '15 at 20:54
  • 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. – dothebart Aug 07 '15 at 17:31
  • 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](https://pypi.python.org/pypi/PyRRD/) 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`). – dr jimbob Aug 07 '15 at 18:08
  • Python's subprocess module can be used safely (without `shell=True`) and is quite useful when you are already familiar with the shell commands to do your task, and this is the sort of task you don't mind accomplishing with a shell script (that is where you aren't optimizing for a few milliseconds of difference per command). I really don't care you downvoted (and its now locked), though I disagree that this was an ["an answer that is clearly and perhaps dangerously incorrect"](http://stackoverflow.com/help/privileges/vote-down) of the sort that should be voted down. – dr jimbob Aug 07 '15 at 18:12
  • I should add you should *never* do this anywhere near something that talks to untrusted contexts (Ie web/network/users who arent your employees/software you didnt write/etc). I've never come across a shell callout or similar construction in a web app I've had to maintain I havent been able to exploit into giving me root access and a shell. *Never* encountered it. Same goes with SQL interpolation. Theres no safe way. – Shayne Sep 16 '20 at 13:01