Flatten a nested directory tree into one folder without losing path context.
src/components/Button.tsx.txt
⬇️
flat/components%2FButton.tsx.txt
flatten-dir copies every file from a nested source directory into a single destination directory, while encoding each file’s original relative path into the new filename.
That gives you a flat folder that still preserves where each file came from.
Before:
src-txt/
├── components/
│ └── Button.tsx.txt
├── pages/
│ └── index.tsx.txt
└── package.json.txt
After:
src-flat/
├── components%2FButton.tsx.txt
├── pages%2Findex.tsx.txt
└── package.json.txt
This is useful when you need to feed many files into tools that prefer or require a flat file list, while still keeping file origin obvious.
Great for:
- Preparing source files for LLM/code-review workflows
- Flattening exported
.txtversions of a codebase - Creating searchable single-directory snapshots
- Archiving nested files without losing path context
- Avoiding vague filenames like
index.txt,index-1.txt,index-final.txt
| Feature | Why it matters |
|---|---|
POSIX sh compatible |
Works without Bash or zsh-specific syntax |
| Path-preserving filenames | Original directory context is encoded into each filename |
| Collision detection | Refuses to silently overwrite files |
| Safe destination handling | Rejects destinations inside the source tree |
| Percent encoding | Avoids lossy _ replacement schemes |
| Metadata preservation | Uses cp -p to preserve timestamps and modes where supported |
Save the script as:
flatten_dir_posix.shMake it executable:
chmod +x flatten_dir_posix.shRun it:
./flatten_dir_posix.sh ./src-txt ./src-flatGiven this source tree:
src-txt/
├── components/
│ └── Button.tsx.txt
├── components/
│ └── Modal.tsx.txt
├── lib/
│ └── api/client.ts.txt
└── README.md.txt
Run:
./flatten_dir_posix.sh ./src-txt ./src-flatOutput:
src-flat/
├── components%2FButton.tsx.txt
├── components%2FModal.tsx.txt
├── lib%2Fapi%2Fclient.ts.txt
└── README.md.txt
The script percent-encodes path separators and awkward filename characters.
| Original | Encoded |
|---|---|
% |
%25 |
/ |
%2F |
: |
%3A |
| space | %20 |
| tab | %09 |
| carriage return | %0D |
| newline | %0A |
This is safer than replacing everything with underscores because underscore-based flattening can create collisions.
These could collide with naive underscore replacement:
a:b.txt
a b.txt
a_b.txt
Percent encoding keeps them distinct.
The script refuses to run when:
- The source directory does not exist
- The destination already exists
- The destination is inside the source directory
- A flattened filename would overwrite an existing file
- A copy operation fails
This is intentional. A flattening tool should be boring, predictable, and hard to misuse.
flowchart TD
A[Source directory tree] --> B[Find files recursively]
B --> C[Compute relative path]
C --> D[Percent-encode path]
D --> E[Copy into destination folder]
E --> F[Flat directory with path-safe filenames]
Uses standard Unix tooling:
shfindawkcpmkdirdirnamebasenamepwdwctrmktemp
Works best on macOS and Linux.
See flatten_dir_posix.sh.
If your gist includes both the zsh and POSIX versions, suggested file names:
flatten_dir.zsh
flatten_dir_posix.sh
README.md
Suggested gist description:
Flatten directory trees safely: POSIX sh and zsh scripts that copy nested files into one folder using collision-resistant, path-encoded filenames
Use freely, modify freely, and ship it wherever it helps.