带通配符的 find -exec

带通配符的 find -exec

我正在尝试使用 bash“find”来处理包含 .log 文件的所有文件夹并获取其大小。但是通配符无法按预期工作。这不会返回任何内容:

find . -type d -exec test -e '{}/*.log' \; -exec du -d0 '{}' \;

但是如果我*.log用替换foo.log,那么它对于包含该文件名的目录就会按预期工作。

根据一些类似的 SE 帖子,我尝试过:

find . -type d -exec bash -c 'test -e "{}/*.log"' \; -exec du -d0 '{}' \;
find . -type d -exec bash -c 'test -e "$1/*.log"' '{}' \; -exec du -d0 '{}' \;

但这些并没有什么效果。

答案1

find … -exec test -e '{}/*.log'你传递一个字符串时,something/*.log比如test*文字。这两种工具都不会将其视为通配符。如果它是参数的一部分(而不是整个参数),则的某些实现find甚至不会扩展。{}{}

您的后续尝试之一嵌入到了{}shell 代码中。切勿嵌入{}shell 代码。这件事上,另一种尝试更好,你离解决方案很近了。这将有点工作:

# still flawed though
find . -type d -exec bash -c 'test -e "$1/"*.log' bash '{}' \; -exec du -d0 '{}' \;

中的第二个 sh 是什么sh -c 'some shell code' sh。然而,主要的“修复”是在 shell 代码中不引用星号。这样它在内 shell 中就是一个通配符(但在外壳中不是,它在那里被正确地单引号括起来)。问题是*.log可能会扩展到多个单词(如果有许多匹配的文件),这种情况会中断调用test

以下代码将查找包含*.log文件的目录:

find . -type d -exec sh -c '
   for f in "$1/"*.log; do test -e "$f" && exit 0; done; exit 1
' sh {} \; -print

代码是可移植的。无需内部bashsh应该会更快。如果愿意,可以-print用替换。-exec du …

exit 0它的工作原理是,一旦确认存在某个匹配文件¹,内壳就会返回成功 ( ) test。尚未测试的匹配文件(如果有)将不会被白白测试,这样可以节省时间。如果没有匹配,则模式将保持文字状态,test将失败,整个外壳将以失败退出 ( exit 1)。记住-exec也是一个测试,因此它会影响是否执行-print(或您放在那里的任何内容)。-exec du …


另一种方法可能是让find自己找到匹配的文件

find . -name '*.log' … -print

并解析其输出以隔离目录名称,最后使用xargsdu目录可能会出现多次,路径名中的换行符将需要不可移植的代码(从 开始-print0)。我认为这会不必要地复杂化。查找目录似乎更胜一筹。


¹ 注释test -e会告诉您是否有文件可以是目录或者其他任何内容. 要确认常规文件是否存在,请使用test -f

答案2

查找/扫描日志文件然后收集唯一的目录名称会更容易。

find命令应拉出目录,添加uniq以删除重复项。-z/-0标志有助于确保完美解析带有换行符/空格/引号的路径名:

find . -type f -name \*.log -exec dirname -z {} \+ | uniq -z | xargs -0 -r du -d0

添加| sort -rn |head是否搜索最大的磁盘使用情况。

相关内容