如何限制 Unix 查找结果数以处理包含许多文件的目录

如何限制 Unix 查找结果数以处理包含许多文件的目录

有没有办法限制 unix 系统上 find 命令返回的结果数?

由于某些目录中的文件数量异常多,我们遇到了性能问题。

我正在尝试做类似的事情:

find /some/log -type f -name *.log -exec rm {} ; | limit 5000

答案1

听起来你正在寻找参数,但还不知道。

find /some/log/dir -type f -name "*.log" | xargs rm

答案2

您可以尝试类似 的操作find [...] |head -[NUMBER]。这将在输出其任意多行时SIGPIPE发送,以便不会继续搜索。findheadfind

警告: find按出现的顺序输出文件在目录结构中。大多数 *NIX 文件系统不按条目名称对目录进行排序。这意味着结果以不可预测的顺序给出。find |sort将按照您的设置定义的排序顺序排列列表LC_COLLATE——在大多数情况下,ASCII 顺序

另一个警告:虽然这种情况在现实中极为罕见,但 *NIX 文件名可以包含换行符。许多程序通过选择性地使用 NUL 字节 ( \0) 作为记录分隔符来解决这个问题。

大多数 *nix 文本处理实用程序都可以选择使用 NUL 作为记录分隔符,而不是换行符。以下是一些示例:

  • grep -z
  • xargs -0
  • find -print0
  • sort -z
  • head -z
  • perl -0

将所有这些放在一起,按字母顺序安全删除前 5000 个文件:

find /some/log -type f -name '*.log' -print0 |
sort -z |
head -5000 -z |
xargs -0 rm

*此处添加了换行符以便于理解,尽管两种语法都是有效的并且作用相同;您可以在一行上执行所有操作(foo | bar | baz),只要确保不删除|分隔命令的(垂直管道)。

答案3

如果您的目录中有大量文件,和/或使用管道可能不适用等,例如因为 xargs 会受到系统允许的参数数量的限制,一种选择是使用命令的退出状态exec作为下一步操作的过滤器,例如:

rm /tmp/count ; find . -type f -exec bash -c 'echo "$(( $(cat /tmp/count) + 1 ))" > /tmp/count' \; -exec bash -c 'test $( cat /tmp/count ) -lt 5000' \; -exec echo "any command instead of echo of this file: {}" \;

第一个命令exec只会增加计数器。第二个命令exec测试计数,如果小于 5000,则以 0 退出并执行下一个命令。第三个命令将对文件执行预期操作,在本例中为简单的 echo,我们也可以执行 -print -delete 等。(例如,exec我会使用-delete而不是。-exec rm {} \;

这一切都基于这样的事实:find假设前一个操作返回 0,则按顺序执行操作。

当使用上述示例时,您需要确保/tmp/count它不会被并发进程使用。

[根据 Scott 的评论进行编辑] 非常感谢 Scott 的评论。

根据他们:该数字已更改为 5,000 以匹配初始线程。

另外:/tmp/count 文件仍将被写入 42,000 次(与被浏览的文件的次数一样多),这是绝对正确的,因此“find”仍将遍历所有 42,000 个条目,但只会执行 5,000 次感兴趣的命令。因此,此命令不会避免浏览整个文件,而只是作为常规管道的替代选项提供。使用内存映射的临时目录来托管此 /tmp/count 文件似乎是合适的。

除了您的评论之外,还有一些额外的编辑:在大多数典型情况下,管道会更简单。

但是,请参见下文以了解更多管道无法轻易应用的原因:

  • 当文件名中有空格时,“find”exec 命令不会忘记用引号“{}”将 {} 括起来,为了支持这种情况,

  • 当预期命令不允许将所有文件名包含在原始文件中时,例如:-exec somespecificprogram -i "{}" -o "{}.myoutput" \;

因此,这个示例本质上是针对那些在处理管道问题时面临挑战但又不想使用更复杂的编程选项的人们发布的。

答案4

|head我来说不起作用:

root@static2 [/home/dir]# find . -uid 501 -exec ls -l {} \; | head 2>/dev/null
total 620
-rw-r--r--  1 root   root           55 Sep  8 15:22 08E7384AE2.txt
drwxr-xr-x  3 lamav statlus 4096 Apr 22  2015 1701A_new_email
drwxr-xr-x  3 lamav statlus 4096 Apr 22  2015 1701B_new_email
drwxr-xr-x  3 lamav statlus 4096 May 11  2015 1701C_new_email
drwxr-xr-x  2 lamav statlus 4096 Sep 24 18:58 20150924_test
drwxr-xr-x  3 lamav statlus 4096 Jun  4  2013 23141_welcome_newsletter
drwxr-xr-x  3 lamav statlus 4096 Oct 31  2012 23861_welcome_email
drwxr-xr-x  3 lamav statlus 4096 Sep 19  2013 24176_welco
drwxr-xr-x  3 lamav statlus 4096 Jan 11  2013 24290_convel
find: `ls' terminated by signal 13
find: `ls' terminated by signal 13
find: `ls' terminated by signal 13
find: `ls' terminated by signal 13
find: `ls' terminated by signal 13

(...ETC...)

我的解决方案(当然不是最好的):

find . -uid 501 -exec ls -l {} \; 2>/dev/null | head

缺点是“查找”本身不会在达到所需的行数后终止,而是在后台运行直到^C或结束,因此欢迎提出想法。

相关内容