find 如何防止无限循环(例如,在查找文件时重命名文件时)?

find 如何防止无限循环(例如,在查找文件时重命名文件时)?

请考虑以下命令:

find . -type f -name '*.*' -exec mv '{}' '{}_foo' \;

find在这种情况下如何防止无限循环?

一方面,我相信知道 find 确实不是像 shell globs 一样工作,即它不会获取所有*.jpg文件的列表,而是在内部存储该列表,然后处理列出条目。相反,它从底层操作系统“增量”处理文件,并在知道后立即处理每个文件(让我们忽略可能发生的一定量的缓冲,因为这与问题无关)。毕竟,据我所知,这是find相对于包含大量文件的目录中的 glob 的主要优点。

如果这是真的,我想了解 find 如何防止无限循环。在上面的示例中,1.jpg将重命名为1.jpg_foo.从 StackOverflow 和其他地方的讨论中,我知道重命名可能会导致文件(名称)占据目录文件列表中的不同位置,因此 find 可能会再次遇到该文件,然后再次将其重命名(为1.jpg_foo_foo),等等在。

显然,这不会发生。

答案1

在单个目录中,它可能就像在处理之前读取整个文件列表一样简单(并strace使其看起来就像发生的那样):

# keep reading entries first
openat(AT_FDCWD, ".", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 4
getdents(4, /* 1024 entries */, 32768)  = 32752
getdents(4, /* 1024 entries */, 32768)  = 32768
getdents(4, /* 426 entries */, 32768)   = 13632
getdents(4, /* 0 entries */, 32768)     = 0
close(4)                                = 0

(为便于阅读而对输出进行了删节)

# process stuff later
clone(...
wait4(...
--- SIGCHLD...
clone(...
wait4(...
--- SIGCHLD ...

但一般来说,find根本不会阻止任何循环。如果将文件移动到子目录,这种情况会发生多次:

mkdir -p sub/sub/sub/sub
find -type f -exec mv {} sub/{}_foo \;

这会导致sub/sub/sub/sub/file_foo_foo_foo_foo诸如此类的事情。 (-depth在这种情况下可能有帮助)。

最好从一开始就避免任何可能的冲突,而不是盲目依赖find使用一些根本不存在的魔法。您在编辑之前提出的问题是一个很好的解决方案,因为它根本与已重命名的文件完全不匹配。

即使在没有严格要求的情况下,最好明确文件不能也不应该被处理两次。我们jpg在这里重命名文件而不是foo文件。

此外,即使find在一次调用中将阻止两次处理文件,整个脚本始终存在重新运行并且 find 将第二次运行的风险,因此无论哪种方式,您都需要采取适当的保护措施。

相关内容