Assuming you know the target is a symbolic link and not a file, is there any difference between using rm
and unlink
to remove the link?
-
4This is pretty well covered on ServerFault: serverfault.com/questions/38816/…– slm ♦Aug 24, 2014 at 19:21
-
@slm♦ The answers correspond to that question, but this question is different, it says: "Assuming you know the target is a symbolic link and not a file".– Stéphane GourichonMar 21, 2015 at 20:02
4 Answers
Anytime you have these types of questions it's best to conceive of a little test to see what's actually happening. For this you can use strace
.
unlink
$ touch file1
$ strace -s 2000 -o unlink.log unlink file1
rm
$ touch file1
$ strace -s 2000 -o rm.log rm file1
When you take a look at the 2 resulting log files you can "see" what each call is actually doing.
Breakdown
With unlink
it's invoking the unlink()
system call:
....
mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f6d025cc000
close(3) = 0
unlink("file1") = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
....
With rm
it's a slightly different path:
....
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
newfstatat(AT_FDCWD, "file1", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
geteuid() = 1000
newfstatat(AT_FDCWD, "file1", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
faccessat(AT_FDCWD, "file1", W_OK) = 0
unlinkat(AT_FDCWD, "file1", 0) = 0
lseek(0, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
close(0) = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
...
The system calls unlink()
and unlinkat()
are essentially the same except for the differences described in this man page: http://linux.die.net/man/2/unlinkat.
The unlinkat() system call operates in exactly the same way as either unlink(2) or rmdir(2) (depending on whether or not flags includes the AT_REMOVEDIR flag) except for the differences described in this manual page.
If the pathname given in pathname is relative, then it is interpreted relative to the directory referred to by the file descriptor dirfd (rather than relative to the current working directory of the calling process, as is done by unlink(2) and rmdir(2) for a relative pathname).
If the pathname given in pathname is relative and dirfd is the special value AT_FDCWD, then pathname is interpreted relative to the current working directory of the calling process (like unlink(2) and rmdir(2)).
If the pathname given in pathname is absolute, then dirfd is ignored.
-
2Since it's giving
AT_FDCWD
, there's effectively no difference betweenunlink
andunlinkat
.– BarmarAug 27, 2014 at 21:01 -
18It makes me happy to read this answer because I just "learned to fish" in a powerful, flexible way when often I get a fish or sometimes I "learn to fish" in a basic way on SO :-)– sageJan 24, 2017 at 19:21
POSIX specifies that the unlink
utility calls the C library unlink
function and nothing else. It takes no option. If you pass a valid path name to something which isn't a directory, and if you have write permissions to the directory where that object lives, then unlink
will remove it.
rm
is a traditional Unix command which has a bit of other functionality, and isn't quite a superset of unlink
(see below).
Firstly, rm
performs safety checks. If you try to rm
an object to which you don't have write permissions (which are irrelevant to your ability to remove it: the containing directory's permissions are!) rm
nevertheless refuses unless -f
is specified. rm
normally complains if the file doesn't exist, as does unlink
; however with -f
, rm
does not complain. This is often exploited in Makefiles (clean: @rm -f $(OBJS) ...
) so make clean
doesn't fail when there is nothing to remove.
Secondly, rm
has the -i
option for interactively confirming the delete.
Thirdly, rm
has -r
for recursively removing a directory, which is something that unlink
isn't required to do, since the C library function doesn't do that.
The unlink
utility isn't exactly a stripped-down rm
. It performs a subset of what rm
does, but it has semantics which is a combination of rm
with -f
and rm without -f
.
Suppose you want to just remove a regular file regardless of what its own permissions are. Furthermore, suppose you want the command to fail if the file doesn't exist, or any other reason. Neither rm file
nor rm -f file
meets the requirements. rm file
will refuse if the file isn't writable. But rm -f file
will neglect to complain if the file is missing. unlink file
does the job.
unlink
was probably introduced because rm
is too clever: sometimes you just want the pure Unix unlink
semantics: "please make this directory entry go away if directory permissions allow".
-
13This is the clearest answer here. It actually gives the use case for
unlink
rather than just describing differences.– WildcardNov 28, 2018 at 21:11 -
Agreed. The unlink(1) tool is just a simple wrapper of unlink(2), without additional features. Jul 13, 2021 at 9:05
With a single file, rm and unlink do the same task, remove the file. As POSIX defined, rm
and unlink
both call to unlink() system call.
In GNU rm
, it calls to unlinkat() system call, which is equivalent to the unlink()
or rmdir() function except in the case where path specifies a relative path.
Note
On some systems, unlink
can also remove directory. At least in GNU system, unlink
can never delete the name of a directory.
Also with rm you can use glob to delete multiple files. With unlink you can delete one file at a time.
touch f{1..10}
rm f* # works
touch f{1..10}
unlink f* # doesn't work (expands to unlink f1 f2 ... f10)
unlink f1 # works