
我在網路上找到了一個for迴圈的例子。現在我想在我的程式碼中使用它,但我不確定這個循環是如何運行的
for entry in "$search_dir"/*
do
echo "$entry"
done
現在我想問一下
- 它是否在每次迭代中查找 search_dir 並將 search_dir 中的檔案複製到每次迭代中的條目變數一個檔案?
- 或者我拍攝 search_dir 的所有內容的快照,然後將該快照儲存到條目變數中?
- 如果有人在循環仍在工作時在 search_dir 中插入一些文件,輸出是否會改變?
答案1
當 shell 到達for
- 語句時,它將擴展 的值$search_dir
並執行檔案名稱通配以產生將迭代的目錄條目清單。這種情況只會發生一次,如果循環執行時 中的內容$search_dir
消失或有新檔案/目錄加入到該目錄中,則這些變更將不會被擷取。
如果循環對名稱為 的目錄條目進行操作$entry
,則可能需要測試它們是否存在於循環中,特別是如果已知循環需要很長時間才能運行,並且有大量文件不斷變化,出於這樣或那樣的原因:
for entry in "$search_dir"/*; do
if [ -e "$entry" ]; then
# operate on "$entry"
else
# handle the case that "$entry" went away
fi
done
正如 Stéphane 在評論中正確指出的那樣,這是一個多餘的測試最多案例。
答案2
shell 在開始運行循環體之前完全確定要循環的值清單。那是:
- shell 使用變數的值來建構路徑
search_dir
。 - shell 收集指定目錄中的檔案名稱列表,以建立通配符模式的匹配列表。
- shell 依序對符合清單中的每個元素執行循環體。
search_dir
您可以在循環運行時變更變數 的值,並變更目錄的內容。這不會影響循環作用於哪些文件。
如果在循環處理其他文件時刪除一個文件,那麼一旦到達該文件,該文件將不存在。根據您在循環中執行的操作,這可能重要也可能不重要。如果存在可能刪除檔案的並發進程,請注意,在處理之前測試檔案是否存在並不能真正解決該問題,因為該文件可能會在您測試和開始處理之間被刪除。
如果您需要將檔案標記為已處理以確保不會處理它兩次,那麼此腳本應在處理完檔案後將其移至另一個目錄。將檔案移到另一個目錄(在同一檔案系統上)是原子:要么尚未完成,要么已經完成,沒有中間狀態。但再一次,如果不同的進程(可能是該腳本的另一個實例)移動文件,那麼循環有時會命中循環執行時移動的文件。
如果您想在建立新文件時對其進行處理,則需要再次循環。顯然,文件可以在循環執行期間創建,或者在處理完所有先前的文件之後創建,因此腳本需要永遠運行。有一些工具可以等待目錄中建立檔案。在 Linux 上,基本功能是inotify;如果您需要在建立文件時對其進行處理,那麼inotifywait
或者因克朗應該對你有幫助。請記住,inotify 僅通知您建立的檔案(或根據您的觸發器修改或存取)後基於 inotify 的命令啟動;您還需要處理先前存在的文件,但您不能這樣做,for entry in *; do …; done; inotifywait …
因為可以在循環執行期間甚至在命令inotifywait
啟動時建立文件。