Filehandles, files, directories
rename#
Change the name of a file.
rename asks the operating system to rebind the path OLDNAME to
NEWNAME. On a POSIX filesystem this is a single atomic directory
operation: after the call returns successfully, NEWNAME refers to
the file that used to be reachable as OLDNAME, and OLDNAME no
longer exists. It is the same primitive the shell mv command
reaches for when source and destination live on the same filesystem.
Synopsis#
rename OLDNAME, NEWNAME
What you get back#
1 on success, 0 on failure with $! set to the errno the
underlying rename(2) syscall returned. Always check the return
value — a silent failure here leaves the filesystem in a state the
rest of the program does not expect:
rename $tmp, $final
or die "rename $tmp -> $final failed: $!";
Atomicity and the same-filesystem rule#
rename is atomic only when OLDNAME and NEWNAME resolve to
the same filesystem. Within that filesystem, no intermediate
state is ever visible: another process reading the directory sees
either the old name or the new name, never both and never neither.
This is why the canonical “write a file safely” idiom writes to a
temporary file in the same directory and then renames it into
place:
open my $fh, ">", "$path.tmp" or die "open: $!";
print $fh $data;
close $fh or die "close: $!";
rename "$path.tmp", $path
or die "rename: $!";
Across filesystems the call fails with EXDEV ("Invalid cross-device link") and nothing is moved. The system mv command papers over
this by falling back to copy-then-unlink; rename does not. For a
portable cross-device move, use move from File::Copy,
which performs the copy-and-unlink fallback itself.
Examples#
Rename within a directory:
rename "draft.txt", "final.txt"
or die "rename: $!";
Atomic file replacement — write to a sibling tempfile, then rename:
my $tmp = "$path.$$.tmp";
open my $fh, ">", $tmp or die "open $tmp: $!";
print $fh $content;
close $fh or die "close $tmp: $!";
rename $tmp, $path or die "rename $tmp -> $path: $!";
Detect the cross-device case and fall back to File::Copy::move:
use Errno qw(EXDEV);
use File::Copy qw(move);
unless (rename $src, $dst) {
if ($! == EXDEV) {
move($src, $dst) or die "move: $!";
}
else {
die "rename: $!";
}
}
Rename every .log in a directory to .log.old:
for my $f (glob "*.log") {
rename $f, "$f.old"
or warn "rename $f: $!";
}
Edge cases#
NEWNAMEalready exists: silently clobbered.renamedoes not ask, warn, or refuse. If the target is a regular file it is unlinked as part of the operation; if it is a directory the call fails withENOTDIRorEISDIRdepending on whetherOLDNAMEis a directory. To get “refuse to overwrite” semantics, test with-efirst (and accept that the check is racy — there is no portablerenameat2(RENAME_NOREPLACE)exposed throughrenameitself).Cross-filesystem (
EXDEV): fails, leaves both paths intact. UseFile::Copy::movewhen the destination may be on another mount.Open filehandles: on Linux (and POSIX generally) renaming a file that is currently open is fine. The open filehandle keeps pointing at the same inode; subsequent reads and writes through it continue to work. New opens use the new name.
Directories: renaming a directory is allowed, but only when
NEWNAMEdoes not exist or is an empty directory. Moving a directory into a subdirectory of itself fails withEINVAL.Permissions:
renameneeds write + execute permission on both the source and destination parent directories, not on the file itself. Failure shows up asEACCESorEPERM.Sticky-bit directories (
/tmp): if the destination parent has the sticky bit set, you must own either the source file or the destination parent; otherwise the call fails withEPERMeven when the directory is world-writable.Symlinks:
renameoperates on the link itself, never on its target.rename "link", "other"renames the symlink; the file it points at is untouched.Trailing slash on
OLDNAME: many kernels reject this withENOTDIRwhen the source is not a directory. Do not rely on trailing-slash behaviour being portable.Same-path rename:
rename $p, $psucceeds and does nothing (POSIX-required behaviour) as long as$pexists.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
unlink— remove a file by name; the tear-down counterpart to creating one withrenameinto placelink— make an additional hard-link name for an existing file without removing the originalsymlink— create a symbolic link; note thatrenameon a symlink moves the link, not its targetFile::Copy— portablemoveandcopythat handle the cross-filesystem (EXDEV) caserenamecannot$!—errnoafter a failedrename; compare against constants fromErrno(EXDEV,EACCES,ENOENT, …)