我需要完全解析路径并相对于给定目录。这必须高效地完成,因为路径的数量通常大于 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/d
和a
, 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
,即使在单处理器系统上也可能会提高效率。
-print0
且xargs -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 --取消引用