Filehandles, files, directories

mkdir#

Create a single directory on the filesystem.

mkdir asks the operating system to create the directory named by FILENAME, with permission bits given by MODE (further restricted by the process umask). It creates exactly one directory — every parent component in FILENAME must already exist. For recursive creation, reach for File::Path::make_path instead.

Synopsis#

mkdir FILENAME, MODE
mkdir FILENAME
mkdir

What you get back#

1 on success, 0 on failure with $! set to the system errno. Unlike most I/O primitives, the failure value is a plain false 0, not undef — check the return value, then consult $! for the reason:

mkdir $path, 0755
    or die "mkdir $path failed: $!";

Default arguments#

Both arguments default:

  • MODE defaults to 0777. The kernel masks the supplied mode with the current process umask, so the directory’s effective mode is MODE & ~umask. A typical umask of 022 turns the default 0777 into 0755 on disk.

  • FILENAME defaults to $_. Bare mkdir; inside a loop over pathnames creates each in turn:

    mkdir for qw(logs cache tmp);
    

Pass MODE explicitly whenever the directory should be private (mail spools, key stores, session directories). Otherwise prefer a permissive MODE and let the user’s umask narrow it — the umask page discusses the trade-off in detail. Setting bits outside the permission range (e.g. setuid/setgid/sticky) yields implementation-defined behaviour per POSIX 1003.1-2008.

Global state it touches#

  • Sets $! (errno) on failure; leaves it untouched on success.

  • Reads FILENAME from $_ when called with no arguments.

  • The effective permission bits depend on the process umask.

Examples#

Create a directory with an explicit mode:

mkdir "build", 0755
    or die "mkdir build: $!";

Create it only if missing, without treating “already there” as an error:

use Errno qw(EEXIST);
unless (mkdir "cache", 0700) {
    die "mkdir cache: $!" unless $! == EEXIST;
}

Private directory — do not let umask widen it:

mkdir "$ENV{HOME}/.secrets", 0700
    or die "mkdir secrets: $!";

Bare form over a list, using $_ as the filename:

for (qw(a b c)) {
    mkdir or warn "mkdir $_: $!";
}

Recursive creation is not mkdir’s job — use File::Path:

use File::Path qw(make_path);
make_path("var/log/app/2026", { mode => 0755 })
    or die "make_path failed: $!";

Edge cases#

  • Parent must exist. mkdir "a/b/c" fails with ENOENT if a/b is missing. Use File::Path::make_path for deep paths.

  • Target already exists. Fails with EEXIST, regardless of whether the existing entry is a directory, file, or symlink. Check $! against Errno::EEXIST when “already there” is acceptable.

  • Trailing slashes. POSIX 1003.1-1996 allows any number of trailing slashes; Perl strips them before the syscall so that filesystems which reject "foo/" still behave consistently.

  • Permission mismatch. MODE is masked by umask. If you need an exact mode on disk, either save and restore the umask, or chmod the directory after creation:

    mkdir $dir, 0700 or die $!;
    chmod 0700, $dir;                   # defeat any umask surprises
    
  • MODE omitted entirely. mkdir $path is mkdir $path, 0777 — still masked by umask, so the on-disk mode is typically 0755, not 0777.

  • Non-permission bits in MODE. Setuid / setgid / sticky bits on a mkdir call have implementation-defined results. Set them with a follow-up chmod if you need them.

  • Read-only filesystem or missing write permission on the parent fails with EROFS or EACCES respectively. $! discriminates.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • rmdir — remove an empty directory; the inverse operation

  • chmod — adjust permission bits after creation when umask would otherwise narrow them

  • umask — the mask that silently restricts every mkdir MODE

  • stat — inspect an existing path’s type and mode, e.g. to distinguish “already a directory” from “exists as a file”

  • File::Path::make_path — recursive directory creation; the right tool when intermediate parents may not exist