APUE2中的混淆(关于UNIX中的符号链接)

时间:2011-09-26 14:39:42

标签: linux unix posix symlink

原文如下。见4.22节

  

图4.24中的程序更改为特定目录,然后调用getcwd以打印工作目录。如果我们运行该程序,我们得到

$ ./a.out
cwd = /var/spool/uucppublic
$ ls -l /usr/spool
lrwxrwxrwx 1 root 12 Jan 31 07:57 /usr/spool -> ../var/spool
     

请注意,chdir遵循我们期望的符号链接,如图4.17所示。但是当它上升到目录树时,getcwd不知道它何时到达/ var / spool目录,它是由符号指向的链接/ usr / spool。这是符号链接的特征。

作者真正的意思是说该程序命中/var/spool? 作者指出的符号链接的特征是什么? 我真的不明白。

3 个答案:

答案 0 :(得分:2)

假设您有一个指向/usr/spool的符号链接/var/spool

它表示如果您遵循该符号链接(例如cd /usr/spool),您最终会进入指向目录(/var/spool)。然后,您遵循符号链接的信息将丢失。您就在/var/spool,就像您直接完成了cd /var/spool一样。

另一个cd ..会将您带到/var(而不是/usr)。

更新

正如Keith Thompson和Jonathan Leffler所指出的,有一些的shell会记住你所遵循的路径(即/usr/spool)。在这样的炮弹中,cd .. 会去/usr/。但是,从这样的shell启动的程序仍然会将/var/spool视为工作目录。

这可能是作者允许您编写用于显示cwd的程序(以解决此类shell'内部)的原因。

答案 1 :(得分:2)

扩展@undor_gongor所写的内容:

每个进程都有一个当前工作目录。它不存储为目录的路径名;它是对目录本身的引用。

如果它被存储为路径名,那么getcwd()函数的作业将是微不足道的:只需打印路径名。相反,它必须读取当前目录,打开其..条目,然后打开该目录的..条目,依此类推,直到它到达根目录(即,..条目的目录指向目录本身)。它以相反的顺序构建当前目录的完整路径。

由于..不能是符号链接,因此此过程不受符号链接的影响。

(Shell可能有一个$PWD$CWD变量,或者pwd内置的,受符号链接影响;这些通常通过记住传递给{的字符串来工作{1}}或cd。)

答案 2 :(得分:2)

请注意,某些shell(尤其是bash)通过追踪符号链接来跟踪您是否到达给定目录,并相应地打印当前目录。至少bash可以选择cd来执行物理或逻辑更改目录:

  

cd [-L|-P] [dir]

     

将当前目录更改为dir。变量HOME是默认目录。 [...] -P选项表示使用物理目录结构而不是跟随符号链接(另请参阅set builtin命令的-P选项); -L选项强制遵循符号链接。 -的参数等价于$ OLDPWD。如果使用CDPATH中的非空目录名,或者-是第一个参数,并且目录更改成功,则新工作目录的绝对路径名将写入标准输出。如果目录已成功更改,则返回值为true;否则就是假的。

在显示的方案中,/usr/spool/var/spool的符号链接,然后:

$ pwd
/
$ cd /usr/spool/uucppublic
/usr/spool/uucppublic
$ cd -L ..
/usr/spool
$ cd /usr/spool/uucppublic
/usr/spool/uucppublic
$ cd -P ..
/var/spool
$

对于大多数人来说,普通cd ..cd -L ..的做法相同。如果您愿意,可以选择bashcd -P ..相同(使用set -Pset -L)。

还应该了解查找当前目录的路径名的过程。逻辑上,进程(内核)打开当前目录(.)并读取inode编号(和设备编号)。然后打开父目录(..),并从中读取条目,直到找到具有匹配的inode编号(和设备编号)的条目。然后,它为它提供路径名的最后一个组件。它现在可以重复该过程,找到下一个目录的inode编号,并打开其父目录(../..)等,直到它到达根目录(两个{{1}的inode编号) }和.是相同的,值通常为2)。请注意,这甚至适用于挂载点。但请注意自动安装的远程(NFS)文件系统;如果你扫描一个包含数百个自动安装机器的目录,它可能会非常慢 - 因为上面的天真搜索大纲会安装所有机器,直到它找到正确的机器。因此,实际的..函数比这更聪明,但它解释了如何找到当前目录的路径。它还说明了在评估getcwd()下的目录时,流程不会遇到/usr/spool的原因 - 它根本不会打开/var/spool/uucppublic目录。

请注意,/usr函数(系统调用)采用可能引用符号链接的名称,并将其解析为根本不包含符号链接的名称。通过realpath()后,它会返回/usr/spool/uucppublic,例如。