从符号链接中区分常规文件


22

我正在编写一个bash脚本,该脚本需要将常规文件与符号链接区分开。我以为我可以使用if / test表达式来做到这一点,但是它不起作用,正如我期望的那样:

$ touch regular_file
$ test -f regular_file; echo $?
0
$ test -h regular_file; echo $?
1
$ ln -s regular_file symlink
$ test -h symlink; echo $?
0
$ test -f symlink; echo $?
0

这是为什么?而且,我该如何正确执行此操作?

Answers:


20

看来您只是在加点测试。您不需要同时运行两个测试,这种情况下唯一需要的就是-h告诉您文件是否为符号链接。

test -h file && echo "is symlink" || echo "is regular file"

-f测试仅告诉您对象是否为文件。这将返回0如果它是一个目录或设备节点或一个符号链接到一个目录,但将返回1上一个符号链接到一个文件中。

如果还需要知道它是否是文件而不是目录的符号链接,则需要将两个测试的结果与一些逻辑结合起来。


正如我从文档理解,之间的差值-e-f被认为-e是用来知道,如果(任何类型)的文件的存在,并且-f被具体测试,如果该文件存在,是一个普通的文件。看来我误解了什么是“普通文件”是... ...
Nupraptor

1
@Nupraptor:是的,您误解了文档。与文件可能具有的其他某些类型的节点(块设备节点,字符设备节点,目录等)相反,符号链接被视为常规文件。如果您想知道文件的类型,则必须运行特定-h于文件类型的测试,例如符号链接,-p命名管道等
。– Caleb,

然后,如何测试文件是否不是管道或符号链接等意义上的常规文件?我是否应该为此提出另一个问题?
Nupraptor 2011年

@Nupraptor:唯一奇怪的情况是链接到常规文件的符号链接。否则,如果它作为常规文件进行测试,则它是常规文件。
David Schwartz

3
test -f目录将返回1而不是0:test -f。; 回声$?(输出1)
多项式

7

@Caleb关于使脚本仅测试符号链接是正确的。但是关于原因的部分被遗漏了,我很好奇。如果查看coreutils源代码并跟踪测试的输出,则可以看到运行符号链接测试时,它使用lstat;如果使用-f测试,则它实际调用“ stat”,该符号紧随符号链接:

$ ln -s varnish_config XXX
$ strace -s 2000 test -L XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-L", "XXX"], [/* 47 vars */]) = 0
lstat("XXX", {st_mode=S_IFLNK|0777, st_size=14, ...}) = 0

$ strace -s 2000 test -L varnish_config 2>&1 | grep varnish
execve("/usr/bin/test", ["test", "-L", "varnish_config"], [/* 47 vars */]) = 0
lstat("varnish_config", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

$ strace -s 2000 test -f XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-f", "XXX"], [/* 47 vars */]) = 0
stat("XXX", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

在统计手册页中:

   stat() stats the file pointed to by path and fills in buf.

   lstat() is identical to stat(), except that if path is a symbolic link,
   then the link itself is stat-ed, not the file that it refers to.

这意味着-f测试将返回true,只要指定的文件名是指向常规文件或常规文件本身的符号链接即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.