我正在嘗試編寫 bash 腳本,在其中嘗試查找某個位置是否有空文件,如果找到則發送電子郵件。我首先想到將“查找”和“郵件”組合在一起,但是如果該位置有多個空文件,它會發送多封郵件,這是我不想要的,所以我想到在查找並設置它之前將標誌變數設定為零到 1 裡面查找是否找到空文件。這是我嘗試過的:
FLAG=0
find $LOCATION -size 0 -type f -exec sh -c 'export FLAG=1' \;
echo $FLAG
但問題是,即使該位置有空文件,標誌值也不會更改為 1。
答案1
set -- "${LOCATION}/"*
while [ -s "$1" ] ; do shift ; done
[ -e "$1" ] && FLAG=1
shell 內建指令[ test ]
可以與ize 運算子一起使用-s
。從man test
:
-s FILE
FILE
存在且大小大於零
但這對於遞歸搜尋來說並不容易。
find
會,但對於像設定布林值這樣簡單的事情,它確實不太適合這種情況。ls
可以同樣快速地進行遞歸搜索,可以輕鬆配置為提供文件大小作為列表的第一個字段,並保證每行僅列出一個條目。如果您想根據遞歸檔案清單是否包含 0 大小的檔案來設定 shell 變數的布林值,那麼這ls
是您最好的選擇 -find
只會使事情變得複雜。您感興趣的是檔案屬性,而不是檔案位置。這就是它的ls
亮點,並且grep
ping 其輸出是輕而易舉的事。
您可以輕鬆地做到這一點:
ls -1aqRsp "$LOCATION" 2>&1 | grep -qv "^ *[^0]\|/"
FLAG=$(($?==0))
這只會設定FLAG
為1
如果文件 -隱 .dot
包含的檔案 - 存在於$LOCATION
或其子目錄之一中,大小為零。否則,$FLAG
是0
.
答案2
find
當你這樣做時,正在分叉一個新的子進程-exec
。任何子進程都不能改變其父進程的環境。
您可以考慮收集有問題的檔案名find
,然後在第二遍中產生您想要的電子郵件:
find . -type f -size 0 -print >> /var/tmp/find.sz0
...
答案3
這是在呼叫的export FLAG=1
實例中執行的。進程的環境永遠不會複製回其父進程。僅設定環境變數並退出的 shell 進程不會完成任何持久任務。sh
find
如果你想測試是否find
符合任何文件,你可以簡單地測試它的輸出是否為空。為了避免可能產生一長串文件,但在證明它非空後才將其丟棄,您可以find
在第一時間截斷輸出。 GNU find 有一個-quit
謂詞,您也可以輕鬆地告訴它顯示單字。在下面的程式碼片段中,FLAG
如果沒有匹配,則結果為空:
FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)
以下變數設定FLAG
為 0 或 1:
FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)
[ -n "$FLAG" ] || FLAG=0
如果您想保持便攜性,您可以進行find
列印配對並僅保留第一行;find
會死於訊號管道head
關閉管道的一側後。
if [ -n "$(find "$LOCATION" -size 0 -type f -print | head -n 1 \;)" ]; then
FLAG=1
else
FLAG=0
fi
如果這只是一個簡化的範例,並且您需要設定更複雜的變量,則有幾種可能的方法。我只提幾個常見的。
Zsh 有很多find
內建的用例,這要歸功於全域限定符。以下程式碼片段設定files
為 符合的檔案清單find $LOCATION -size 0 -type f
:
files=(**/*(.DL0))
set -o globstar
如果分別使用和啟用,Ksh 和 bash 也具有遞歸 glob shopt -s globstar
。但請注意,bash 到 4.2 版本時,**
會遞歸到目錄的符號鏈接,這通常是不可取的。您可以在 shell 中進行進一步的處理。
FIGNORE= # include dot files in wildcard matches (the ksh way)
GLOBIGNORE=.:.. # include dot files in wildcard matches (the bash way)
for x in **/*; do
done
如果符合的檔案名稱都不包含換行符,您可以將 的輸出解析為find
換行符分隔清單。
find "$LOCATION" -size 0 -type f ! -name '*
*' -print | {
while read -r empty_file; do
…
done
}