將“for file in”轉換為“find”,以便我的腳本可以遞歸應用
我有這樣的想法,即執行一個 bash 腳本來檢查一些條件,並使用
ffmpeg
它來將我目錄中的所有影片從任何格式轉換為.mkv
,它工作得很好!問題是,我不知道
for file in
循環不能遞歸工作(https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively)但我幾乎不理解“管道”,並期待看到一個例子並清除一些不確定性。
我想到了這種情況,我認為這對我理解有很大幫助。
假設我有這個 bash 腳本片段:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
它的作用是,對於目前目錄,搜尋任何
*.mkv *avi *mp4 *flv *ogg *mov
然後聲明輸出具有其副檔名,.mkv
然後刪除原始文件,然後輸出應保存到原始影片所在的同一文件夾中。
- 如何將其轉換為遞歸執行?如果我使用
find
,在哪裡聲明變數$file
?你應該在哪裡申報$target
?都是find
真的單行嗎?我真的需要將文件傳遞給一個變數$file
,因為我仍然需要執行條件檢查。- 並且,假設(1)成功,如何確保滿足“然後輸出應保存到原始影片所在的同一文件夾”的要求?
你有這個程式碼:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
在目前目錄中執行。要將其轉換為遞歸過程,您有幾個選擇。最簡單的(IMO)是
find
按照您的建議使用。for 的語法find
非常“不像 UNIX”,但這裡的原則是每個參數都可以與 AND 或 OR 條件一起應用。在這裡,我們要說“如果 this-filename 匹配 OR that-filename 匹配 Then print-it ”。文件名模式被引用,因此 shell 無法獲取它們(請記住,shell 負責擴展所有未引用的模式,因此如果您有一個未引用的模式*.mp4
並且您janeeyre.mp4
在目前目錄中,shell 將替換*.mp4
為匹配,並且find
會看到-name janeeyre.mp4
而不是您想要的-name *.mp4
;如果*.mp4
匹配多個名稱…)。括號加上前綴\
也可以防止外殼嘗試將它們作為子外殼標記(如果願意,我們可以引用括號來代替:)'('
。find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print
它的輸出需要輸入到
while
依次處理每個文件的循環的輸入中:while IFS= read file ## IFS= prevents "read" stripping whitespace do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
現在剩下的就是用管道將這兩個部分連接在一起,
|
以便輸出find
成為while
循環的輸入。當您測試此程式碼時,我建議您在兩者
ffmpeg
和rm
with前加上前綴,echo
這樣您就可以看到將執行的內容 - 以及使用哪些路徑。這是最終結果,包括
echo
我推薦用於測試的語句:find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print | while IFS= read file ## IFS= prevents "read" stripping whitespace do target="${file%.*}.mkv" echo ffmpeg -i "$file" "$target" && echo rm -rf "$file" done
使用 POSIX 查找:
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o \ -name '*ogg' -o -name '*mov' \) -exec sh -c ' for file do target="${file%.*}.mkv" echo ffmpeg -i "$file" "$target" done' sh {} +
替換
echo
為您要使用的任何命令。如果你有 GNU find 或 BSD find,你可以使用
-regex
:find . -regex '.*\.\(mkv\|avi\|mp4\|flv\|ogg\|mov\)'