Glob Find All Files In Subfolders

9 min read

Glob find all files in subfolders is a common task for developers, system administrators, and data scientists who need to locate every file matching a certain pattern deep inside a directory tree. Still, whether you are cleaning up temporary files, gathering assets for a build process, or scanning logs for analysis, knowing how to wield glob patterns efficiently saves time and reduces errors. This guide explains what globbing is, shows practical examples in Python, Bash, and PowerShell, highlights common mistakes, and offers performance tips so you can reliably retrieve every file you need—no matter how nested the folder structure Took long enough..

Understanding Glob Patterns

A glob is a simple wildcard syntax used by shells and many programming libraries to match file names. The most familiar symbols are:

  • * – matches any sequence of characters except a directory separator (/ on Unix, \ on Windows).
  • ? – matches exactly one character.
  • [abc] – matches any single character inside the brackets (e.g., [0-9] for a digit).
  • {foo,bar} – expands to either foo or bar (supported in Bash and some libraries).

When you want to glob find all files in subfolders, you need a pattern that descends into directories. In many environments the double‑asterisk ** serves this purpose: it matches zero or more directories recursively. Day to day, not all glob implementations support ** natively, so you sometimes combine it with other tools (like find or os. walk) to achieve true recursion Which is the point..

Using Glob in Python

Python’s glob module (available since Python 3.5) understands the ** pattern when you pass the recursive=True flag. This makes it straightforward to glob find all files in subfolders with just a few lines of code.

Basic Example

import glob

# Find every .txt file in the current directory and all subdirectories
txt_files = glob.glob('**/*.txt', recursive=True)
print(txt_files)
  • **/*.txt tells glob to match any number of directories (**) followed by any name ending in .txt.
  • Setting recursive=True activates the recursive behavior; without it, ** is treated as a literal asterisk pair.

Filtering with Multiple Extensions

If you need several file types at once, combine patterns with a list comprehension:

patterns = ['**/*.py', '**/*.ipynb', '**/*.md']
all_files = []
for pat in patterns:
    all_files.extend(glob.glob(pat, recursive=True))

# Remove duplicates that may appear if a file matches more than one pattern
unique_files = list(set(all_files))
print(f"Found {len(unique_files)} files")

Using pathlib (Modern Alternative)

Starting with Python 3.4, pathlib.Path offers an object‑oriented approach that also supports recursive globbing:

from pathlib import Path

root = Path('.')
py_files = list(root.rglob('*.

`rglob` automatically adds the `**` prefix, making the intent clear: “search recursively for *.py*”.

### Handling Hidden Files

By default, glob does **not** return entries that start with a dot (`.`). To include hidden files, you must explicitly match them:

```python
hidden_logs = glob.glob('**/.*log', recursive=True)

Be cautious when combining hidden‑file patterns with normal ones; you may inadvertently match parent directory entries like ...

Using Glob in Bash

Bash’s built‑in pathname expansion also supports ** when the globstar option is enabled. This lets you glob find all files in subfolders directly from the command line without invoking external utilities No workaround needed..

Enabling globstar

shopt -s globstar   # enable ** recursion

After this, patterns like **/*.log work as expected Easy to understand, harder to ignore. Practical, not theoretical..

Practical Examples

  • List all JPEG images

    echo **/*.jpg
    
  • Count files

    shopt -s nullglob   # prevents literal pattern return when no matches
    files=(**/*.txt)
    echo "${#files[@]} text files found"
    
  • Perform an action on each match

    for f in **/*.bak; do
        echo "Removing backup: $f"
        rm -i "$f"
    done
    

Combining with Other Tools

Sometimes you need more complex selection criteria (size, modification time, etc.). In those cases, pipe glob results to while read or use find:

# Find files larger than 10 MB
shopt -s globstar nullglob
for f in **/*; do
    [[ -f "$f" && $(stat -c%s "$f") -gt 10485760 ]] && echo "$f"
done

Using Glob in PowerShell

PowerShell treats * and ?So as wildcards in many cmdlets, and the -Recurse parameter provides directory traversal. While PowerShell does not use the ** syntax natively, you can achieve the same effect with Get-ChildItem Not complicated — just consistent..

Simple Recursive Search

# Get all .csv files in the current folder and all subfolders
Get-ChildItem -Path . -Filter *.csv -Recurse -File
  • -Filter limits the match to the given extension.
  • -Recurse tells PowerShell to descend into subdirectories.
  • -File ensures only files (not directories) are returned.

Using Wildcards in -Include / -Exclude

If you need multiple patterns, -Include accepts an array:

Get-ChildItem -Path . -Recurse -File -Include *.log, *.txt

Advanced Filtering with Where-Object

For conditions beyond name patterns (e.g., file size), pipe to Where-Object:

Get-ChildItem -Path . -Recurse -File |
    Where-Object { $_.Length -gt 5MB } |
    Select-Object FullName, Length

Common Pitfalls and How to Avoid Them

Pitfall Symptom Solution
Forgetting to enable globstar in Bash **/*.So txt Run shopt -s globstar before using the pattern. So naturally, txtreturns the literal string**/*. joinorpathlibin Python; in Bash, enablenocaseglobif needed, or use\as separator. or use -not -name ".glob without recursive=True
Path separators mismatch on Windows Patterns with / fail Use `os.
Using glob.path. entries Explicitly filter out names starting with .*" in find. Consider this: or.. Plus,
Matching hidden files unintentionally Scripts process `.
Performance degradation on huge trees Script hangs or consumes excessive memory Limit scope with -maxdepth (find) or process results in streams (generators) rather than building large lists.

Performance Considerations for Large Codebases

When working with repositories containing tens of thousands of files, the mechanics of pattern expansion become a bottleneck. Day to day, the shell expands globs before executing the command, meaning rm **/*. Now, log passes every single matching path as a distinct argument to rm. This hits the kernel’s ARG_MAX limit and consumes significant memory Worth keeping that in mind..

Streaming with find + xargs

For bulk operations, find combined with xargs (or find -exec ... +) streams results in manageable batches, avoiding argument limits entirely.

# Safe deletion of millions of .tmp files
find . -type f -name '*.tmp' -print0 | xargs -0 rm -f
  • -print0 / -0 handle filenames with spaces, newlines, or quotes safely.
  • xargs batches arguments automatically (typically 128KB chunks).

Parallel Execution

Modern multi-core systems benefit from parallel processing. GNU parallel or xargs -P can use all cores for CPU-bound tasks like compression or linting Most people skip this — try not to. Turns out it matters..

# Compress all .log files using 4 parallel workers
find . -type f -name '*.log' | parallel -j4 gzip --best {}

Python: Generators over Lists

In Python, glob.glob and pathlib.Path.rglob return lists, loading all paths into memory. For massive trees, os.scandir (used internally by pathlib in 3.11+) or glob.iglob (iterator version) keeps memory usage constant (O(1)) Simple, but easy to overlook..

# Memory-efficient iteration (Python 3.5+)
import glob
for filepath in glob.iglob('**/*.log', recursive=True):
    process_log(filepath)  # Process one at a time

Cross-Platform Portability Strategies

Writing glob logic that behaves identically on Linux, macOS, and Windows requires abstracting filesystem differences.

Normalize Separators Early

Never hardcode / or \. Use the standard library abstractions It's one of those things that adds up..

Language Correct Approach
Python `pathlib.js**
Node.Join("src", "", "*.So js', { windowsPathsNoEscape: true })`
Go filepath. Glob(filepath.go")) (requires doublestar lib for **)
Rust `glob::Pattern::new("**/*.

Case Sensitivity

  • Linux/macOS (APFS default): Case-sensitive. *.txt misses README.TXT.
  • Windows/macOS (default): Case-insensitive.

Portable Fix: Explicitly define case handling.

  • Bash: shopt -s nocaseglob (makes current shell case-insensitive).
  • Python: glob.glob(pattern, recursive=True, case_sensitive=False) (3.10+).
  • PowerShell: Inherently case-insensitive; use -CaseSensitive switch on operators if strict matching is needed.

Handling Symlinks and Junctions

Recursive globs follow symlinks by default in Python (pathlib) and find -L, but not in Bash ** or PowerShell Get-ChildItem. Infinite loops occur if a symlink points to a parent directory.

Defensive Pattern:

# Bash: Avoid loops, ignore symlinks to directories
shopt -s globstar dotglob
for f in **/*.conf; do
    [[ -L "$f" && -d "$f" ]] && continue  # Skip symlinked directories
    process "$f"
done

Modern Alternatives: fd and ripgrep

For interactive use and CI pipelines, modern Rust-based tools replace find/grep/glob combinations with faster, smarter defaults (respecting .gitignore, hidden files, parallelism) But it adds up..

Tool Use Case Glob Equivalent
fd Finding files by name fd '\.rs
Just Added

The Latest

Kept Reading These

Cut from the Same Cloth

Thank you for reading about Glob Find All Files In Subfolders. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home
≈ find . Even so, -name '*. Plus, rs'
rg (ripgrep) Finding content inside files rg 'TODO' ≈ grep -r 'TODO' .
fd -e rs Extension filter `**/*.

Example: Delete build artifacts safely

# Dry run first
fd -e o -e so -e class -t f -X rm -v
# -e: extension, -t f: type file, -X: execute command per file

These tools are generally 5–50x faster than shell built-ins on large trees because they parallelize directory traversal and avoid stat syscall overhead where possible Which is the point..

Summary: Choosing the Right Tool

Scenario Recommended Approach
Quick interactive cleanup (Bash/Zsh)

Complete Summary & Recommendations

Scenario Recommended Approach
Quick interactive cleanup (Bash/Zsh) Use fd or rg with dry-run flags; they abstract platform quirks while offering safety checks.
Cross-platform build scripting Prefer native standard libraries (pathlib in Python, Glob in Go/Rust) over third-party tools when performance isn't critical. Think about it:
Content search inside code use rg (ripgrep) as it combines pattern matching, speed, and intelligent context extraction without requiring manual path normalization. Day to day,
CI/CD pipeline artifact collection Combine fd for file enumeration with shell operations only for final execution—this minimizes network round-trips and preserves cross-platform compatibility. Consider this:
Configuration discovery Use rg -t yaml -I '. git/' to find all YAML files excluding version control, then normalize paths with your language-specific abstraction early in the chain.

Final Thoughts

Building truly portable glob logic is less about finding the most feature-rich tool and more about understanding the constraints each environment imposes. The core principle remains consistent: normalize early, handle edge cases explicitly, and prefer well-tested standard library primitives whenever possible. While modern utilities like fd and ripgrep have closed many gaps left by traditional shell globbing, they introduce their own dependencies and may require adjustments for very specific project layouts.

When you encounter inconsistent behavior across platforms, treat it as a signal to adopt one of these strategies before proceeding further: abstract the path manipulation into a single function that dispatches to the appropriate implementation based on the target runtime, or standardize your development workflow around the most common deployment target (typically Linux/macOS for containerized workloads). This approach ensures that your codebase remains resilient whether it runs locally on any platform or in production environments spanning multiple operating systems.

By investing time in writing defensively against filesystem idiosyncrasies now, you eliminate a whole class of subtle bugs—those that appear only under specific OS configurations or when running in containers—that can be painful to debug later. The initial effort pays dividends in maintainability and reliability throughout the software lifecycle Which is the point..

Most guides skip this. Don't.

Just Added

The Latest

Kept Reading These

Cut from the Same Cloth

Thank you for reading about Glob Find All Files In Subfolders. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home