如何有效地取消引用 `find` *output* 文件名中的所有符号链接?

如何有效地取消引用 `find` *output* 文件名中的所有符号链接?

我需要完全解析路径并相对于给定目录。这必须高效地完成,因为路径的数量通常大于 100,000 条。

情况:我有包含以下内容的目录大多到其他目录的符号链接,如

foo
 123 -> ../baz/123
 896 -> ../bar/896

(请注意, foo 不仅包含目录的符号链接,它还包含我也必须捕获的普通文件。)

这些符号链接目录包含文件。我想获取这些文件的列表,格式如下

baz/123/some.file
bar/123/other.file

也就是说,当“find”找到符号链接时,我希望它取消引用该路径当它报告内容时

所以我从 foo 的父目录运行此命令:

find -L foo -type f

但这是行不通的。

老实说,您会期望-L声称“遵循符号链接”的选项来实现此行为。但是,其实际的行为就是看进入这些目录的内容,但报告其中的文件及其非取消引用的名称,即。结果看起来像

foo/baz/123/some.file
foo/bar/896/another.file

结果将用于针对全为 1 的文件路径列表进行设置操作。完全解决和 2.相对于 foo 的父目录,因此每个结果也必须满足该标准。我可以保证出于这些目的,所有链接都是可解析的,即。没有一个是圆形的或过深的。大多数(但不是全部)链接指向目录而不是文件。

目前,我能做的最好的事情就是使用一个 Python 脚本将所有未解除引用的路径重写为已解析的路径。但由于涉及的文件数量在100000+范围,这不是很实用(而且相当荒谬,因为find已经费心去取消引用它们,它只是没有返回取消引用的路径)。 (编辑:请参阅我对这篇文章的评论 - 我发现了一个非解决方案(因为它有效地完成了工作,但以错误的方式 - 执行外部命令)。)

我确信我应该能够仅使用find外部命令来完成此任务,但我没有找到这里的手册页启发 - -L, -H, -P,-follow都没有正确的行为,-printf %l.-exec出于明显的原因而被排除——它不是 内部的find。有任何想法吗?

编辑2:在这一点上,斯蒂芬已经说服我,没有特别好的理由为什么要找到内部有这个功能,所以我愿意接受任何合理有效的答案。

答案1

find在一般情况下,您所要求的没有多大意义,因此没有任何规定也就不足为奇了。

具有相对目标的符号链接是相对于符号链接的路径的。例如,如果通过跟随符号链接遍历目录,find遇到a/b/c/da, a/b,a/b/c都是相对或绝对符号链接(或带有符号链接组件的路径的符号链接),那么应该做什么?

如果您正在寻找扩展为的find谓词或 GNU指令-printf %相对于当前目录或任何目录的无符号链接的文件路径,恐怕没有。

如果您使用的是 Linux,则可以使用以下命令获取这些文件的绝对路径:

find -L foo -type f -exec readlink -f {} \;

正如您所发现的,至少存在一个realpath命令可以接受多个路径参数,该命令与标准-exec cmd {} +语法相结合将会更加高效,因为它运行的实际路径命令数量尽可能少:

find -L foo -type f -exec realpath {} +

find -L foo -type f -print0 | xargs -r0 realpath

realpath可能会更快,就好像需要多个命令一样,find可以在第一个命令开始工作时继续查找更多文件realpath,即使在单处理器系统上也可能会提高效率。

-print0xargs -r0不是标准的,来自 GNU,但在许多其他实现(例如大多数现代 BSD)中都可以找到。

Zsh 对其有内置支持:

print -rl foo/***/*(-.:A)

如果您不关心排序顺序,可以通过以下方式禁用排序并提高效率:

print -rl foo/***/*(-.oN:A)

如果你想将它们转换为当前目录的相对路径,你可以看看那么问题

如果您知道所有这些文件在当前目录内都有一个绝对规范路径(其所有组件都不是符号链接),您可以将其简化为(仍然使用zsh):

files=(foo/***/*(-.:A))
print -rl -- ${files#$PWD/}

虽然简短且方便,并且可以使用任何字符文件名包含的内容,但我怀疑它会比find+更快realpath

使用 Debianrealpath和 GNU 工具,您可以:

cd -P .
find -L foo -type f -exec realpath -z {} + | 
  gawk -v p="$PWD" -v l="${#PWD}" -v RS='\0' -vORS='\0' '
    substr($0, 1, l+1) == p "/" {$0 = substr($0, l+2)}; 1' |
  xargs -r0 whatever you want to do with them

我现在意识到,现在有一个realpath最新版本的 GNU coreutils,它具有您正在寻找的功能,所以这只是一个问题

find -L foo -type f -print0 |
  xargs -r0 realpath -z --relative-base . |
  xargs -r0 whatever you want to do with them

(如果您想要相对路径,甚至对于其符号链接自由路径不在当前工作目录下方的文件,请使用--relative-to .而不是)。--relative-base .

答案2

ls -1 -R --取消引用 |厕所-l

为我成功了。但我只需要计算文件数量,递归地挖掘到任何符号链接的目的地。我不需要展示它们。但既然你这样做了,只需删除管道和字数,简单如下:

ls -1 -R --取消引用

相关内容