我正在嘗試使用 bash“查找”來處理包含 .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
to 這樣的字串時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 程式碼中引用星號。這樣,它在內殼中是一個通配符(但在外殼中不是,它在那裡被正確地單引號引用)。問題是*.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
該代碼是可移植的。不需要inner bash
,sh
應該更快。如果您願意,請替換-print
為。-exec du …
exit 0
其工作原理是,一旦test
確認某些匹配文件的存在,就從內殼返回成功( )。尚未測試的配對文件(如果有)不會被白白測試,這樣可以節省時間。如果沒有匹配,則模式將保持原義,test
將失敗,整個 shell 將因失敗而退出 ( 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
如果搜尋最大的磁碟使用量,請新增。