我正在尝试使用 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
代码是可移植的。无需内部bash
,sh
应该会更快。如果愿意,可以-print
用替换。-exec du …
exit 0
它的工作原理是,一旦确认存在某个匹配文件¹,内壳就会返回成功 ( ) test
。尚未测试的匹配文件(如果有)将不会被白白测试,这样可以节省时间。如果没有匹配,则模式将保持文字状态,test
将失败,整个外壳将以失败退出 ( exit 1
)。记住-exec
也是一个测试,因此它会影响是否执行-print
(或您放在那里的任何内容)。-exec du …
另一种方法可能是让find
自己找到匹配的文件
find . -name '*.log' … -print
并解析其输出以隔离目录名称,最后使用xargs
。du
目录可能会出现多次,路径名中的换行符将需要不可移植的代码(从 开始-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
是否搜索最大的磁盘使用情况。