A modern, cross-platform, production-ready replacement for mkdir — brace
expansion, mixed / and \ path separators, safe force-recreate, colored +
emoji output, JSON reports, dry-run, and more.
$ mkdir2 -v project/{src,tests,docs}
✅ created: project/src
✅ created: project/tests
✅ created: project/docs
The classic mkdir is fine, but it hasn't changed in decades and it behaves
differently depending on the shell and platform you're using. mkdir2 is a
single static binary that works the same way everywhere:
- One path syntax, every OS.
data\2024\reportsanddata/2024/reportscreate the exact same tree, whether you're on Linux, macOS, or Windows. - Brace expansion, like Bash, but built in — no shell required, so it works identically from PowerShell, cmd.exe, or any script runner.
- Safe, explicit "force recreate" instead of a fragile
rm -rf && mkdirtwo-step. - Scriptable output:
--json,--stats,--quiet, and proper exit codes for use in CI and automation. - Themeable: pick your own hex colors, or turn color/emoji off entirely for log files and dumb terminals.
cargo install mkdir2git clone https://github.com/cumulus13/mkdir2
cd mkdir2
cargo install --path .Prebuilt binaries for Linux (gnu/musl), macOS (x86_64/aarch64), and Windows are attached to every GitHub release.
mkdir2 [OPTIONS] [PATH]...
# Plain creation, parents included by default (like mkdir -p)
mkdir2 build/output
# Brace expansion — creates three directories in one call
mkdir2 project/{src,tests,docs}
# Nested + cartesian expansion
mkdir2 build/{debug,release}/{bin,lib}
# Numeric ranges, with zero-padding preserved
mkdir2 file{01..10}
# Either separator works on every platform
mkdir2 "data\2024\reports"
mkdir2 "data/2024/reports" # identical result
# Force: delete an existing tree first, then recreate it clean
mkdir2 --force old_output
# Preview without touching the filesystem
mkdir2 --dry-run new_stuff/{a,b,c}
# Batch-create from a file, one pattern per line
mkdir2 --from dirs.txt --gitkeepNote for Bash/zsh users:
\is always treated as a path separator by mkdir2, the same as/. But on an interactive Unix shell, an unquoted backslash is consumed by the shell itself as an escape character before mkdir2 ever sees it — somkdir2 test\ medoes not createtest/me; it creates a single directory namedtest me(the shell strips the\and keeps the space literal). Likewisemkdir2 test\mebecomes a single directorytestme(the shell deletes the\entirely). To actually use\as a separator from Bash/zsh, quote the argument so the shell leaves it alone:mkdir2 'test\me'creates nestedtest/meas expected. This only matters for interactive Unix shells — it's a non-issue on Windows shells, and on patterns read from a--fromfile, since neither goes through Unix shell escaping.
Note for Windows CMD users: CMD splits arguments on spaces before mkdir2 receives them, so an unquoted pattern like
mkdir2 test2\{test3, test4}arrives as two broken fragments —test2\{test3,andtest4}— and no expansion fires. Always wrap patterns that contain spaces in double quotes:mkdir2 "test2\{test3, test4}". CMD does not give\any special meaning inside double quotes, so the full pattern reaches mkdir2 intact and works correctly. PowerShell behaves the same way: use double quotes for any pattern with spaces.
| Flag | Description |
|---|---|
[PATH]... |
Directories to create. Supports brace expansion and either / or \ as a separator on any platform. |
--from <FILE> |
Read additional path patterns from a file, one per line (- for stdin). Blank lines and # comments are ignored. |
--no-parents |
Disable automatic parent creation (classic strict mkdir behavior). Parents are created by default. |
-f, --force |
Delete an existing target first, then recreate it. |
--no-recursive-remove |
With --force, only remove existing empty directories instead of recursive trees. |
-i, --interactive |
Confirm before deleting an existing path with --force. |
-m, --mode <MODE> |
Octal permissions for new directories, e.g. 0755 (Unix only; warns and no-ops on Windows). |
--gitkeep |
Create a .gitkeep file inside every newly created directory. |
-v, --verbose |
Print each action as it happens. |
-q, --quiet |
Suppress all non-error output. |
-n, --dry-run |
Show what would be done without changing the filesystem. |
--stats |
Print a created/skipped/failed summary at the end. |
--json |
Emit a machine-readable JSON report instead of text. |
--strict |
Treat an already-existing target as an error (matches plain mkdir's strict behavior). |
--color <auto|always|never> |
Control colored output. Honors NO_COLOR and TTY detection in auto mode. |
--no-emoji |
Disable emoji icons in output. |
--color-success/error/warn/info <HEX> |
Customize each message type's color, e.g. --color-info '#00FFFF'. |
Run mkdir2 --help for the full reference.
mkdir2 implements Bash-compatible brace expansion:
| Pattern | Expands to |
|---|---|
{a,b,c} |
a, b, c |
{a,{b,c}} |
a, b, c (nested groups) |
{1..5} |
1, 2, 3, 4, 5 |
{01..05} |
01, 02, 03, 04, 05 (zero-padding preserved) |
{1..10..2} |
1, 3, 5, 7, 9 (step) |
{a..e} |
a, b, c, d, e |
a{1,2}b{x,y} |
a1bx, a1by, a2bx, a2by (cartesian product) |
Spaces around commas are trimmed automatically.
{dir2, dir3}and{dir2,dir3}produce identical results — the leading/trailing whitespace around each item is stripped before expansion. This means accidental spaces after commas will never create directories with leading-space names.
$ mkdir2 --json batch/{a,b,c}
{
"created": 3,
"already_existed": 0,
"skipped": 0,
"failed": 0,
"results": [
{ "path": "batch/a", "action": "created", "message": null },
{ "path": "batch/b", "action": "created", "message": null },
{ "path": "batch/c", "action": "created", "message": null }
]
}Exit code is non-zero if any target failed, even with --json, so it's
safe to check $? in scripts.
| Feature | mkdir |
mkdir2 |
|---|---|---|
| Creates parent dirs | only with -p |
by default (--no-parents to opt out) |
| Brace expansion | only via shell (Bash) | built in, every platform/shell |
/ and \ both work |
no | yes, on every OS |
| Safe recreate-if-exists | no | --force (with --no-recursive-remove, -i) |
| Colored / emoji output | no | yes, fully themeable hex colors |
| Machine-readable output | no | --json |
| Dry-run preview | no | -n / --dry-run |
| Batch creation from a file | no | --from FILE |
cargo build
cargo test
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warningsIssues and pull requests are welcome at github.com/cumulus13/mkdir2.
MIT © Hadi Cahyadi
