请考虑以下命令:
find . -type f -name '*.*' -exec mv '{}' '{}_foo' \;
Run Code Online (Sandbox Code Playgroud)
find在这种情况下如何防止无限循环?
一方面,我相信要知道,发现并没有像贝壳水珠工作要做,即它不获取所有的列表*.jpg文件,存储了列表内部,然后处理该列表中的条目。相反,它从底层 O/S 获取文件以“增量”处理,并在知道后立即处理每个文件(让我们忽略可能发生的一定量的缓冲,因为这与问题无关)。毕竟,据我所知,这是在find包含大量文件的目录中优于 glob的主要优势。
如果这是真的,我想了解 find 如何防止无限循环。在上面的示例中,1.jpg将重命名为1.jpg_foo. 从 StackOverflow 和其他地方的讨论中,我知道重命名可能会导致文件(名称)在目录文件列表中占据不同的位置,因此很可能第二次找到该文件,再次将其重命名(为1.jpg_foo_foo),等等在。
显然,这不会发生。
在单个目录中,它可能就像在处理之前读取整个文件列表一样简单(并且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
Run Code Online (Sandbox Code Playgroud)
(为了可读性而删节了输出)
# process stuff later
clone(...
wait4(...
--- SIGCHLD...
clone(...
wait4(...
--- SIGCHLD ...
Run Code Online (Sandbox Code Playgroud)
但是,一般来说,find根本不会阻止任何循环。如果您将文件移动到子目录,则会多次发生这种情况:
mkdir -p sub/sub/sub/sub
find -type f -exec mv {} sub/{}_foo \;
Run Code Online (Sandbox Code Playgroud)
这导致sub/sub/sub/sub/file_foo_foo_foo_foo诸如此类的事情。(-depth在这种情况下可能会有所帮助)。
最好首先避免任何可能的冲突,而不是盲目地依赖find使用一些不存在的魔法。您在编辑之前的问题是一个很好的解决方案,因为它根本不匹配已重命名的文件。
即使在没有严格要求的情况下,最好明确说明文件不能也不应该被处理两次。我们在jpg这里重命名文件而不是foo文件。
此外,即使find在一次调用中会阻止处理文件两次,脚本作为一个整体将重新运行并且 find 将运行第二次的风险始终存在,因此您需要采取任何一种保护措施。