Try on DesignSafe

Directory Contents#

Listing files and directories with os.listdir

by Silvia Mazzoni, DesignSafe, 2025

Once you’ve confirmed that a path exists, you can explore its contents using Python.
The simplest way to do this is with os.listdir, which returns a list of all files and folders inside the specified directory.

File handling in Python lives in two main places:

  • os/os.path: low-level, battle‑tested utilities (list directories, join paths, check existence).

  • pathlib: a modern, object‑oriented layer that makes paths feel like first‑class objects (with methods for globbing, reading, writing, etc.).

When you need wildcards like *.out or *Lcol12.out, don’t shell out to ls. Instead, use Python’s built‑ins (glob or pathlib.Path.glob) so your code is portable, safe, and testable.

import os
# Test Path:
myPath = '~/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp'
dataDir =os.path.abspath(os.path.expanduser(myPath))

print('thisPath:',dataDir)
print('exists:',os.path.exists(dataDir))
thisPath: /home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp
exists: True

os.listdir(): Simple Directory Listing#

os.listdir(path) returns all entries (files and subdirectories) in a directory—no filtering by pattern:

entries = os.listdir(dataDir)          # Just names, not full paths
entries_full = [os.path.join(dataDir, e) for e in entries]

for i in range(min(10,len(entries_full))):
    print(entries_full[i])
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol141.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol149.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol139.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol144.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol143.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol142.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol209.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol148.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol138.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol145.0.out

Key points

  • Returns everything in the directory (files + subdirs).

  • No pattern matching—you must filter yourself:

Lcol = 100.0
matches = [f for f in entries if f.endswith(f"Lcol{Lcol}.out")]

for i in range(min(10,len(matches))):
    print(matches[i])
DBase_Lcol100.0.out
DCol_Lcol100.0.out
DFree_Lcol100.0.out
FCol_Lcol100.0.out
RBase_Lcol100.0.out
  • Names are returned without the directory prefix; prepend dataDir if you need full paths.

  • Order is not guaranteed; sort if you care about stable output:

entries = sorted(os.listdir(dataDir))

for i in range(min(10,len(entries))):
    print(entries[i])
DBase_Lcol10.0.out
DBase_Lcol100.0.out
DBase_Lcol1000.0.out
DBase_Lcol1001.0.out
DBase_Lcol1002.0.out
DBase_Lcol1003.0.out
DBase_Lcol1004.0.out
DBase_Lcol1005.0.out
DBase_Lcol1006.0.out
DBase_Lcol1007.0.out

Use os.listdir() when you want a quick, unconditional list of contents and you’ll handle filtering in Python.


Wildcards the Right Way: glob and pathlib#

Unlike os.listdir(), which returns all files in a directory without filtering, the glob module lets you use wildcard patterns (***, ?, [ranges]) to match specific filenames — similar to how you would in a shell command like *ls .txt.

glob.glob()#

import glob, os

pattern = os.path.join(dataDir, f"*Lcol{Lcol}.out")
files = sorted(glob.glob(pattern))      # sort for predictable order
for f in files:
    print(f)
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DFree_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/FCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/RBase_Lcol100.0.out

pathlib.Path.glob()#

from pathlib import Path

files = sorted(Path(dataDir).glob(f"*Lcol{Lcol}.out"))
for p in files:
    print(p)                            # Path objects; str(p) if you need strings
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DFree_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/FCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/RBase_Lcol100.0.out

Recursive matching (subdirectories too) uses **:

from pathlib import Path

icnt = 0
for p in Path(dataDir).rglob("*.out"):  # or Path(dataDir).glob("**/*.out")
    print(p)
    icnt += 1
    if icnt>10:
        break
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol141.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol149.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol139.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol144.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol143.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol142.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol209.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol148.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol138.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol145.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol151.0.out

Why not os.system(‘ls …’)?#

While this works on Unix‑like systems:

os.system(f'ls {dataDir}/*Lcol{Lcol}.out')
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DFree_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/FCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/RBase_Lcol100.0.out
0

…it’s usually a bad trade‑off:

  • Not cross‑platform: ls doesn’t exist on Windows (without extra tooling).

  • Brittle: spaces or special characters in paths can break the shell command.

  • Security risk: string interpolation into a shell command can open injection vulnerabilities.

  • No return values: you get printed text, not a list you can manipulate in Python.

  • Harder to test & maintain.

Prefer:

  • glob.glob() / pathlib.Path.glob() for patterns.

  • os.listdir() + Python filtering for simple rules.

Why use glob instead of os.system(‘ls …’)?#

  • Cross-platform — works on Windows, macOS, and Linux

  • No shell dependency — safer, avoids shell injection risks

  • Python-native — returns a list of matching filenames for direct processing


Quick Comparison#

Task / Feature

os.listdir()

glob.glob()

pathlib.Path.glob()

List directory contents

✅ (all entries)

✅ (only matches)

✅ (only matches)

Wildcards (*, ?, [])

Recursive search

✅ with ** + recursive=True

✅ via rglob() or glob("**/pattern")

Returns

Names (no dir)

Matching paths (strings)

Matching paths (Path objects)

Path operations (join, parent, stem)

Manual with os.path

Manual with os.path

Built-in via Path methods

Cross‑platform & safe

Sorted results guaranteed

❌ (use sorted(...))

❌ (wrap with sorted(...))

❌ (wrap with sorted(...))

Example of recursive glob (stdlib style):

import glob, os
pattern = os.path.join(dataDir, "**", "*.out")
files = sorted(glob.glob(pattern, recursive=True))
for f in files[0:min(10,len(files))]:
    print(f)             # line-by-line like `ls`
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol10.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1000.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1001.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1002.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1003.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1004.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1005.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1006.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol1007.0.out

Drop‑in Replacement for ls {dataDir}/*Lcol{Lcol}.out#

import glob, os

pattern = os.path.join(dataDir, f"*Lcol{Lcol}.out")
files = sorted(glob.glob(pattern))
for f in files[0:min(10,len(files))]:
    print(f)             # line-by-line like `ls`
print('')
# or:
print(" ".join(files))   # single line, space-separated
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DFree_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/FCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/RBase_Lcol100.0.out

/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out /home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DCol_Lcol100.0.out /home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DFree_Lcol100.0.out /home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/FCol_Lcol100.0.out /home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/RBase_Lcol100.0.out

Pathlib version

from pathlib import Path

files = sorted(Path(dataDir).glob(f"*Lcol{Lcol}.out"))

for p in files[0:min(10,len(files))]:
    print(p)
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DFree_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/FCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/RBase_Lcol100.0.out

Best Practices & Gotchas#

  • Always sort if order matters:

files = sorted(files)

for p in files[0:min(10,len(files))]:
    print(p)
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DBase_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/DFree_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/FCol_Lcol100.0.out
/home/jupyter/MyData/tapis-jobs-archive/2025-08-14Z/1739a4ea-bc83-419b-9a6d-7823b81c797c-007/inputDirectory/DataTCLmp/RBase_Lcol100.0.out
  • Prefer pathlib in new code; it reads cleaner and reduces os.path boilerplate.

  • Be explicit about recursion: rglob("*.ext") or glob("**/*.ext", recursive=True).

  • Avoid shelling out for path tasks—keep logic in Python for portability, safety, and easier testing.

  • Windows notes: paths are handled correctly by os.path/pathlib; wildcard matching is done by Python, not the shell, so behavior is consistent across OSes.

Splitting into files and directories#

To organize this output more clearly, you can separate files and directories using list comprehensions and os.path.isdir:

AllContents = os.listdir(dataDir)
directories = [name for name in AllContents if os.path.isdir(os.path.join(dataDir, name))]

print(f" -- directories:",directories[:20]); # show only the first few
 -- directories: []
files = [name for name in AllContents if not os.path.isdir(os.path.join(dataDir, name))] # select files as not directories

print(f" -- files:",files[:20]); # show only the first few
 -- files: ['DBase_Lcol141.0.out', 'DBase_Lcol149.0.out', 'DBase_Lcol139.0.out', 'DBase_Lcol144.0.out', 'DBase_Lcol143.0.out', 'DBase_Lcol142.0.out', 'DBase_Lcol209.0.out', 'DBase_Lcol148.0.out', 'DBase_Lcol138.0.out', 'DBase_Lcol145.0.out', 'DBase_Lcol151.0.out', 'DBase_Lcol140.0.out', 'DBase_Lcol14.0.out', 'DBase_Lcol15.0.out', 'DBase_Lcol146.0.out', 'DBase_Lcol147.0.out', 'DBase_Lcol195.0.out', 'DBase_Lcol150.0.out', 'DBase_Lcol208.0.out', 'DBase_Lcol137.0.out']

Why this is helpful#

  • You get a quick overview of what’s inside your data folder.

  • Separating files vs. directories is especially useful if your scripts process only data files, or need to recursively explore subfolders.

  • The list of files is stored in an array so you can use it in your workflow

Recipe Box: Common File Listing Patterns#

These short examples cover frequent file-listing tasks using glob, pathlib, and os.


1. List Only Files (no directories)#

import os
files_only = [f for f in os.listdir(dataDir) 
              if os.path.isfile(os.path.join(dataDir, f))]

Pathlib version:

from pathlib import Path
files_only = [p for p in Path(dataDir).iterdir() if p.is_file()]

2. List Only Directories#

dirs_only = [d for d in os.listdir(dataDir) 
             if os.path.isdir(os.path.join(dataDir, d))]

Pathlib version:

dirs_only = [p for p in Path(dataDir).iterdir() if p.is_dir()]

3. Match by Suffix / Extension#

import glob, os
txt_files = glob.glob(os.path.join(dataDir, "*.txt"))

Pathlib version:

txt_files = list(Path(dataDir).glob("*.txt"))

4. Match by Prefix#

prefixed = [f for f in os.listdir(dataDir) if f.startswith("run_")]

5. Recursive Search (all subfolders)#

import glob, os
pattern = os.path.join(dataDir, "**", "*.out")
files = glob.glob(pattern, recursive=True)

Pathlib version:

files = list(Path(dataDir).rglob("*.out"))

6. Natural Sort (sort by embedded numbers, like file2, file10)#

import re

def natural_key(s):
    return [int(text) if text.isdigit() else text.lower()
            for text in re.split(r'(\d+)', str(s))]

files = sorted(Path(dataDir).glob("*.out"), key=natural_key)

7. Combine Multiple Patterns#

from itertools import chain
import glob, os

patterns = ["*.tcl", "*.py"]
matches = list(chain.from_iterable(
    glob.glob(os.path.join(dataDir, pat)) for pat in patterns
))

Pathlib version:

matches = []
for pat in ["*.tcl", "*.py"]:
    matches.extend(Path(dataDir).glob(pat))

8. Ignore Certain Files#

files = [f for f in os.listdir(dataDir)
         if not f.endswith(".bak") and not f.startswith("temp")]

9. Get Full Paths for All Matches#

full_paths = [os.path.join(dataDir, f) for f in os.listdir(dataDir)]

Pathlib version:

full_paths = list(Path(dataDir).iterdir())

10. Mixed Example: List .out files containing Lcol12, sorted#

import glob, os
pattern = os.path.join(dataDir, "*Lcol12*.out")
files = sorted(glob.glob(pattern))
for f in files:
    print(f)

Python Paths & Wildcards — Quick Reference Cheat Sheet#

here’s a one-page visual cheat sheet laid out like a quick-reference poster so you can instantly compare os, glob, and pathlib patterns for the same task.

Task

os module

glob module

pathlib module

List all entries in a directory

os.listdir(path)

Path(path).iterdir()

List only files

[f for f in os.listdir(path) if os.path.isfile(os.path.join(path,f))]

[p for p in Path(path).iterdir() if p.is_file()]

List only directories

[d for d in os.listdir(path) if os.path.isdir(os.path.join(path,d))]

[p for p in Path(path).iterdir() if p.is_dir()]

Match pattern in current dir

glob.glob("*.txt")

Path(path).glob("*.txt")

Match pattern with subfolders

glob.glob("**/*.txt", recursive=True)

Path(path).rglob("*.txt")

Match by prefix

[f for f in os.listdir(path) if f.startswith("run_")]

[p for p in Path(path).iterdir() if p.name.startswith("run_")]

Match by suffix

[f for f in os.listdir(path) if f.endswith(".txt")]

glob.glob("*.txt")

Path(path).glob("*.txt")

Full path for matches

[os.path.join(path,f) for f in os.listdir(path)]

[os.path.abspath(p) for p in glob.glob("*.txt")]

list(Path(path).glob("*.txt")) (already full path)

Sorted results

sorted(os.listdir(path))

sorted(glob.glob("*.txt"))

sorted(Path(path).glob("*.txt"))

Multiple patterns

chain.from_iterable(glob.glob(p) for p in ["*.tcl","*.py"])

list(chain.from_iterable(Path(path).glob(p) for p in ["*.tcl","*.py"]))

Natural sort

(custom key with re)

(same custom key)

(same custom key)


Tips for Choosing a Method#

  • os.listdir() — fastest for raw directory listings, but no pattern matching. Use with filtering logic.

  • glob.glob() — simplest for wildcards (*, ?, [abc]), supports recursive search.

  • pathlib.Path.glob() / .rglob() — modern, chainable, works well with other path operations (.name, .stem, .suffix).


Example: Cross-Platform Replacement for#

os.system(f'ls {dataDir}/*Lcol{Lcol}.out')
import glob, os

pattern = os.path.join(dataDir, f"*Lcol{Lcol}.out")
files = sorted(glob.glob(pattern))
for f in files:
    print(f)

Pathlib version:

from pathlib import Path

files = sorted(Path(dataDir).glob(f"*Lcol{Lcol}.out"))
for p in files:
    print(p)