Unix 目录递归和符号链接

Unix 目录递归和符号链接,unix,recursion,directory,symlink,Unix,Recursion,Directory,Symlink,如果使用显而易见的方法递归遍历目录树,那么当符号链接指向父目录时,将遇到无限递归的问题 一个显而易见的解决方案是只检查符号链接,而不遵循它们。但对于一个不希望在其他方面(如完全正常的目录)的行为被默默忽略的用户来说,这可能是一个令人不快的惊喜 另一种解决方案可能是保留一个到目前为止访问过的所有目录的哈希表,并使用它来检查循环。但这需要有一些规范化的表示,以某种方式获得您当前正在查看的目录的标识(无论您通过什么路径到达它) Unix用户通常会认为第二种解决方案不那么令人惊讶吗 如果是这样的话,有没

如果使用显而易见的方法递归遍历目录树,那么当符号链接指向父目录时,将遇到无限递归的问题

一个显而易见的解决方案是只检查符号链接,而不遵循它们。但对于一个不希望在其他方面(如完全正常的目录)的行为被默默忽略的用户来说,这可能是一个令人不快的惊喜

另一种解决方案可能是保留一个到目前为止访问过的所有目录的哈希表,并使用它来检查循环。但这需要有一些规范化的表示,以某种方式获得您当前正在查看的目录的标识(无论您通过什么路径到达它)

Unix用户通常会认为第二种解决方案不那么令人惊讶吗


如果是这样的话,有没有一种方法可以获得跨Unix系统可移植的目录的规范表示/标识?(我希望它能够跨Linux、BSD、Mac OS、Solaris等平台工作。我希望必须为Windows编写单独的代码。)

既然您还没有指定使用哪种语言(如果有的话),那么让我们从shell开始:如果您使用的是GNU
readlink
系统,只需使用
readlink-f
将其规范化即可

如果您使用的是Mac电脑(其非GNU
readlink
表现不同),请参阅以了解完成相同任务的方法

另一个选项是使用inode id来跟踪唯一的文件(通过
stat
或类似方式),但无论如何都需要首先跟踪所有符号链接(因为符号链接本身有自己唯一的inode id),跟踪所有符号链接的最简单方法是
readlink


或者,许多编程语言都绑定到POSIX
realpath
函数,该函数基本上执行与
readlink-f
相同的功能(但作为库调用)。例如,Python有,C在
stdlib.h
中有它作为函数,等等


如果您已经在使用具有此功能的语言,强烈建议您使用它,因为您通常可以免费获得跨平台兼容性(假设您的语言是跨平台的)。

目录的绝对路径就是这样一种表示。您可以通过POSIX标准中定义的
realpath
函数获得它,因此它可以在任何符合POSIX标准的系统上工作。不仅要查看符号链接,还要查看硬链接。不是很常见,但不是禁止的。(只有根目录才能硬链接目录)
唯一规范的是{device_number,inode_number}。但是网络文件系统可能会出现问题。

许多应用程序都必须解决相同文件的问题,例如,检查文件双文本(缩进内容、不同名称)和作用于整个目录层次结构的实用程序,如
tar

一个好的实现不希望通过指向父目录或文件的符号链接为硬链接文件和符号链接文件提供误报

解决这个问题的最方便的方法是通过查看POSIX stat/fstat函数和它们用
st_dev
st_ino
成员填充的
struct stat
来识别文件。
采用此策略的C中文件复制检查器的实际实现是(另一个实现是1998年的获奖作品:-)

此领域中最常被忽略的API是

Nftw有避免它遍历符号链接的选项。它拥有比这更先进的能力。以下是手册页本身的一个简单示例:

#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

static int
display_info(const char *fpath, const struct stat *sb,
             int tflag, struct FTW *ftwbuf)
{
    printf("%-3s %2d %7jd   %-40s %d %s\n",
           (tflag == FTW_D) ?   "d"   : (tflag == FTW_DNR) ? "dnr" :
           (tflag == FTW_DP) ?  "dp"  : (tflag == FTW_F) ?   "f" :
           (tflag == FTW_NS) ?  "ns"  : (tflag == FTW_SL) ?  "sl" :
           (tflag == FTW_SLN) ? "sln" : "???",
           ftwbuf->level, (intmax_t) sb->st_size,
           fpath, ftwbuf->base, fpath + ftwbuf->base);
    return 0;           /* To tell nftw() to continue */
}

int
main(int argc, char *argv[])
{
    int flags = 0;

    if (argc > 2 && strchr(argv[2], 'd') != NULL)
        flags |= FTW_DEPTH;
    if (argc > 2 && strchr(argv[2], 'p') != NULL)
        flags |= FTW_PHYS;

    if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags)
            == -1)
    {
        perror("nftw");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}
\define\XOPEN\u源代码500
#包括
#包括
#包括
#包括
#包括
静态整数
显示信息(const char*fpath、const struct stat*sb、,
int tflag,结构FTW*ftwbuf)
{
printf(“%-3s%2d%7jd%-40s%d%s\n”,
(tflag==FTW_D)?“D”:(tflag==FTW_DNR)?“DNR”:
(tflag==FTW\U DP)?“DP”:(tflag==FTW\U F)?“F”:
(tflag==FTW_-NS)?“NS”:(tflag==FTW_-SL)?“SL”:
(tflag==FTW_SLN)?“SLN”:,
ftwbuf->level,(intmax_t)sb->st_尺寸,
fpath,ftwbuf->base,fpath+ftwbuf->base);
返回0;/*以通知nftw()继续*/
}
int
main(int argc,char*argv[])
{
int标志=0;
如果(argc>2&&strchr(argv[2],'d')!=NULL)
标志|=FTW|U深度;
如果(argc>2&&strchr(argv[2],'p')!=NULL)
旗帜|=FTW|U PHYS;
如果(nftw((argc<2)“):argv[1],显示信息,20,标志)
== -1)
{
佩罗(“nftw”);
退出(退出失败);
}
退出(退出成功);
}
另见