如何透過 find+exec 設定變數?

如何透過 find+exec 設定變數?

我正在嘗試編寫 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亮點,並且grepping 其輸出是輕而易舉的事。

您可以輕鬆地做到這一點:

ls -1aqRsp "$LOCATION" 2>&1 | grep -qv "^ *[^0]\|/"
FLAG=$(($?==0))

這只會設定FLAG1如果文件 - .dot包含的檔案 - 存在於$LOCATION或其子目錄之一中,大小為零。否則,$FLAG0.

答案2

find當你這樣做時,正在分叉一個新的子進程-exec。任何子進程都不能改變其父進程的環境。

您可以考慮收集有問題的檔案名find,然後在第二遍中產生您想要的電子郵件:

find . -type f -size 0 -print >> /var/tmp/find.sz0
...

答案3

這是在呼叫的export FLAG=1實例中執行的。進程的環境永遠不會複製回其父進程。僅設定環境變數並退出的 shell 進程不會完成任何持久任務。shfind

如果你想測試是否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
}

相關內容