How to list only top level directories in Python?
PythonFilesystemsPython Problem Overview
I want to be able to list only the directories inside some folder. This means I don't want filenames listed, nor do I want additional sub-folders.
Let's see if an example helps. In the current directory we have:
>>> os.listdir(os.getcwd())
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'mod_p
ython-wininst.log', 'NEWS.txt', 'pymssql-wininst.log', 'python.exe', 'pythonw.ex
e', 'README.txt', 'Removemod_python.exe', 'Removepymssql.exe', 'Scripts', 'tcl',
'Tools', 'w9xpopen.exe']
However, I don't want filenames listed. Nor do I want sub-folders such as \Lib\curses. Essentially what I want works with the following:
>>> for root, dirnames, filenames in os.walk('.'):
... print dirnames
... break
...
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'Scripts', 'tcl', 'Tools']
However, I'm wondering if there's a simpler way of achieving the same results. I get the impression that using os.walk only to return the top level is inefficient/too much.
Python Solutions
Solution 1 - Python
os.walk
Use os.walk
with next
item function:
next(os.walk('.'))[1]
For Python <=2.5 use:
os.walk('.').next()[1]
How this works
os.walk
is a generator and calling next
will get the first result in the form of a 3-tuple (dirpath, dirnames, filenames). Thus the [1]
index returns only the dirnames
from that tuple.
Solution 2 - Python
Filter the result using os.path.isdir() (and use os.path.join() to get the real path):
>>> [ name for name in os.listdir(thedir) if os.path.isdir(os.path.join(thedir, name)) ]
['ctypes', 'distutils', 'encodings', 'lib-tk', 'config', 'idlelib', 'xml', 'bsddb', 'hotshot', 'logging', 'doc', 'test', 'compiler', 'curses', 'site-packages', 'email', 'sqlite3', 'lib-dynload', 'wsgiref', 'plat-linux2', 'plat-mac']
Solution 3 - Python
Filter the list using os.path.isdir to detect directories.
filter(os.path.isdir, os.listdir(os.getcwd()))
Solution 4 - Python
directories=[d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]
Solution 5 - Python
Note that, instead of doing os.listdir(os.getcwd())
, it's preferable to do os.listdir(os.path.curdir)
. One less function call, and it's as portable.
So, to complete the answer, to get a list of directories in a folder:
def listdirs(folder):
return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
If you prefer full pathnames, then use this function:
def listdirs(folder):
return [
d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
if os.path.isdir(d)
]
Solution 6 - Python
This seems to work too (at least on linux):
import glob, os
glob.glob('*' + os.path.sep)
Solution 7 - Python
Using list comprehension,
[a for a in os.listdir() if os.path.isdir(a)]
I think It is the simplest way
Solution 8 - Python
Just to add that using os.listdir() does not "take a lot of processing vs very simple os.walk().next()[1]". This is because os.walk() uses os.listdir() internally. In fact if you test them together:
>>>> import timeit
>>>> timeit.timeit("os.walk('.').next()[1]", "import os", number=10000)
1.1215229034423828
>>>> timeit.timeit("[ name for name in os.listdir('.') if os.path.isdir(os.path.join('.', name)) ]", "import os", number=10000)
1.0592019557952881
The filtering of os.listdir() is very slightly faster.
Solution 9 - Python
A very much simpler and elegant way is to use this:
import os
dir_list = os.walk('.').next()[1]
print dir_list
Run this script in the same folder for which you want folder names.It will give you exactly the immediate folders name only(that too without the full path of the folders).
Solution 10 - Python
Python 3.4 introduced the pathlib
module into the standard library, which provides an object oriented approach to handle filesystem paths:
from pathlib import Path
p = Path('./')
[f for f in p.iterdir() if f.is_dir()]
Solution 11 - Python
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]
Solution 12 - Python
being a newbie here i can't yet directly comment but here is a small correction i'd like to add to the following part of ΤΖΩΤΖΙΟΥ's answer :
> If you prefer full pathnames, then use this function:
>
def listdirs(folder):
return [
d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
if os.path.isdir(d)
]
for those still on python < 2.4: the inner construct needs to be a list instead of a tuple and therefore should read like this:
def listdirs(folder):
return [
d for d in [os.path.join(folder, d1) for d1 in os.listdir(folder)]
if os.path.isdir(d)
]
otherwise one gets a syntax error.
Solution 13 - Python
You could also use os.scandir
:
with os.scandir(os.getcwd()) as mydir:
dirs = [i.name for i in mydir if i.is_dir()]
In case you want the full path you can use i.path
.
> Using scandir() instead of listdir() can significantly increase the > performance of code that also needs file type or file attribute > information, because os.DirEntry objects expose this information if > the operating system provides it when scanning a directory.
Solution 14 - Python
2021 answer using glob
:
import glob, os
p = "/some/path/"
for d in glob.glob(p + "*" + os.path.sep):
print(d)
Solution 15 - Python
For a list of full path names I prefer this version to the other solutions here:
def listdirs(dir):
return [os.path.join(os.path.join(dir, x)) for x in os.listdir(dir)
if os.path.isdir(os.path.join(dir, x))]
Solution 16 - Python
scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]
Solution 17 - Python
FWIW, the os.walk
approach is almost 10x faster than the list comprehension and filter approaches:
In [30]: %timeit [d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]
1.23 ms ± 97.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [31]: %timeit list(filter(os.path.isdir, os.listdir(os.getcwd())))
1.13 ms ± 13.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [32]: %timeit next(os.walk(os.getcwd()))[1]
132 µs ± 9.34 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Solution 18 - Python
Like so?
>>>> [path for path in os.listdir(os.getcwd()) if os.path.isdir(path)]
Solution 19 - Python
A safer option that does not fail when there is no directory.
def listdirs(folder):
if os.path.exists(folder):
return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
else:
return []
Solution 20 - Python
Using python 3.x with pathlib.Path.iter_dir
$ mkdir tmpdir
$ mkdir -p tmpdir/a/b/c
$ mkdir -p tmpdir/x/y/z
$ touch tmpdir/a/b/c/abc.txt
$ touch tmpdir/a/b/ab.txt
$ touch tmpdir/a/a.txt
$ python --version
Python 3.7.12
>>> from pathlib import Path
>>> tmpdir = Path("./tmpdir")
>>> [d for d in tmpdir.iterdir() if d.is_dir]
[PosixPath('tmpdir/x'), PosixPath('tmpdir/a')]
>>> sorted(d for d in tmpdir.iterdir() if d.is_dir)
[PosixPath('tmpdir/a'), PosixPath('tmpdir/x')]
Solution 21 - Python
-- This will exclude files and traverse through 1 level of sub folders in the root
def list_files(dir):
List = []
filterstr = ' '
for root, dirs, files in os.walk(dir, topdown = True):
#r.append(root)
if (root == dir):
pass
elif filterstr in root:
#filterstr = ' '
pass
else:
filterstr = root
#print(root)
for name in files:
print(root)
print(dirs)
List.append(os.path.join(root,name))
#print(os.path.join(root,name),"\n")
print(List,"\n")
return List