2017-02-25 63 views
3

我正嘗試使用FFmpeg將視頻轉換爲Bash中的圖像。我想使用視頻的文件名來命名相應的圖像(後跟一個整數)。提取文件名以命名其他文件時出錯

我能做到這一點,如果我是在同一個目錄導出文件:

for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 $file'_'%d.jpeg; done 

但是,如果我的圖像導出到所需的目錄,我得到了錯誤。看到$ file的值不僅僅是文件名,而是一個目錄。

我試圖:

for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 ~/testfolder/$file'_'%d.jpeg; done 

我的問題是:我怎麼能正確地只提取文件名,這裏使用?

回答

4

這樣做,因爲它可以處理包含任何特殊字符(包括換行符,很少使用但文件名有效)的文件。

destdir=~/testfolder/ 
while read -u 5 -r -d '' file 
do 
    name=$(basename "$file") 
    ffmpeg -i "$file" -q 1 "$destdir/${file}_%d.jpeg" </dev/null 
done 5< <(find . -name "*.mp4" -print0) 

basename命令是一個外部程序。您只需使用shell擴展即可獲得與以下行相同的結果:

name=${file%/} 
name=${name##*/} 
+1

請注意,您可能需要將'ffmpeg'的標準輸入從'/ dev/null'重定向,以使其不會從'find'命令的輸出中讀取。 – chepner

+0

我爲循環添加了一個文件描述符,並從'/ dev/null'重定向了'ffmpeg'輸入。 'ffmpep'實際上是從標準輸入中讀取的,還是更常見的預防措施? – Fred

-1

bash命令basename可用於此目的。

在這種情況下,下面應該只列出文件:

for file in $(find . -name "*.mp4"); do echo $(basename $file); done 

您可以使用$(basename $file)在你原來的代碼只獲取文件名。

for file in $(find . -name "*.mp4"); do 
    ffmpeg -i "${file}" -q 1 "~/testfolder/$(basename $file)'_'%d.jpeg" 
done 
+0

非常感謝,@Danny!有用!爲了澄清,我需要用〜/ testfolder/$(basename $ file)替換〜/ testfolder/$ file'_'%d.jpeg'_'%d.jpeg – Shawn

+0

啊是的 - 我錯過了它被使用了兩次。我已經更正了現在的答案。如果有效 - 您能否將其標記爲已接受的答案? –

+0

剛剛做到了!再次感謝! – Shawn

2

您不需要任何基本名稱也不需要循環; 您可以使用-type f來避免find報告其結果中的目錄以及-exec選項直接執行您的命令。

像這樣的東西應該爲你的所有的MP4文件的工作:

find . -type f -name '*.mp4' -exec bash -c 'ffmpeg -i $0 -q 1 $0'_'%d.jpeg' {} \; 

看到一個小的演示測試:

$ find . -type f -name 'a*.txt' -exec bash -c 'echo ffmpeg -i $0 ' {} \; 
ffmpeg -i ./a.txt 
ffmpeg -i ./a spaced file.txt 
ffmpeg -i ./aa.txt 
ffmpeg -i ./cheatsheets/awk-cheat-sheet-gv.txt 

正如你可以看到第二個文件中有空格的文件名,但通過find正確處理。
相反,這樣的間隔文件將與for loop打破。

如果你堅持用循環做這項工作,那麼這個必須是Fred建議的一個while循環。

作爲修改弗雷德的解決方案,你可以使用find-printf能力避免使用基本名稱的:

while read -r -d '' file;do 
    ffmpeg -i "$file" -q 1 "${file}_%d.jpeg" 
done < <(find . -name "*.mp4" -printf %f\\0) 

-printf %f根據find打印手冊頁的文件名剝離,並追加\\0(NULL字符)在每個文件名後,我們確保正確的文件名處理,即使名稱包含空格或其他特殊字符。

小測試:

$ while read -r -d '' file;do echo "ffmpeg -i $file -q 1 ${file}_%d.jpeg";done < <(find . -name "a*.txt" -printf %f\\0) 
ffmpeg -i a.txt -q 1 a.txt_%d.jpeg 
ffmpeg -i a spaced file.txt -q 1 a spaced file.txt_%d.jpeg 
ffmpeg -i aa.txt -q 1 aa.txt_%d.jpeg 
ffmpeg -i awk-cheat-sheet-gv.txt -q 1 awk-cheat-sheet-gv.txt_%d.jpeg 
+0

嗯 - 這個解決方案不會把輸出文件放到目的地 - 直接寫入輸入文件夾 - 我不認爲這是OP在這裏要求的。我不認爲它實際上回答了這個問題。 –

+0

我不認爲它不起作用。 find的-exec部分不是由我自己構建的,而是由OP構建的('ffmpeg -i $ 0 -q 1 $ 0'_'%d.jpeg')。我只是將它包含在查找中,沒有更多。 –