Saya memiliki ide untuk menjalankan skrip bash untuk memeriksa beberapa kondisi dan menggunakan ffmpeg
untuk mengonversi semua video di direktori saya dari format apa pun ke .mkv
dan itu bekerja dengan baik!
Masalahnya, saya tidak tahu bahwa for file in
loop tidak bekerja secara rekursif (https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively)
Tapi saya hampir tidak mengerti "piping" dan saya menantikan untuk melihat contoh dan menyelesaikan beberapa ketidakpastian.
Saya memikirkan skenario ini yang menurut saya akan banyak membantu saya untuk memahami.
Misalkan saya memiliki cuplikan skrip bash ini:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Apa yang dilakukannya adalah, untuk direktori saat ini, cari *.mkv *avi *mp4 *flv *ogg *mov
apa saja kemudian mendeklarasikan output untuk memiliki ekstensi menjadi .mkv
kemudian setelah itu hapus file aslinya, maka outputnya harus disimpan ke folder yang sama dengan video aslinya.
-
Bagaimana saya bisa mengonversi ini agar berjalan secara rekursif? jika saya menggunakan
find
, di mana mendeklarasikan variabel$file
? Dan di mana Anda harus mendeklarasikan$target
? Apakah semuafind
hanya benar-benar satu kalimat? Saya benar-benar perlu meneruskan file ke variabel$file
, karena saya masih perlu menjalankan pemeriksaan kondisi. -
Dan, dengan asumsi bahwa (1) berhasil, bagaimana memastikan bahwa persyaratan "maka output harus disimpan ke folder yang sama dengan video asli" terpenuhi?
Jawaban yang Diterima:
Anda mendapatkan kode ini:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
yang berjalan di direktori saat ini. Untuk mengubahnya menjadi proses rekursif Anda memiliki beberapa pilihan. Cara termudah (IMO) adalah menggunakan find
seperti yang Anda sarankan. Sintaks untuk find
sangat "tidak seperti UNIX" tetapi prinsipnya di sini adalah bahwa setiap argumen dapat diterapkan dengan kondisi AND atau OR. Di sini, kita akan mengatakan “Jika nama file ini cocok ATAU nama file itu cocok, maka cetaklah “. Pola nama file dikutip sehingga shell tidak dapat menangkapnya (ingat bahwa shell bertanggung jawab untuk memperluas semua pola yang tidak dikutip, jadi jika Anda memiliki pola *.mp4
yang tidak dikutip dan Anda memiliki janeeyre.mp4
di direktori Anda saat ini, shell akan menggantikan *.mp4
dengan kecocokan, dan find
akan melihat -name janeeyre.mp4
alih-alih -name *.mp4
yang Anda inginkan; semakin parah jika *.mp4
cocok dengan beberapa nama…). Tanda kurung diawali dengan \
juga untuk menjaga agar Shell tidak mencoba menjalankannya sebagai penanda subkulit (sebagai gantinya, kita dapat mengutip tanda kurung, jika diinginkan:'('
).
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print
Keluaran ini perlu dimasukkan ke dalam masukan while
loop yang memproses setiap file secara bergantian:
while IFS= read file ## IFS= prevents "read" stripping whitespace
do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Sekarang yang tersisa hanyalah menggabungkan kedua bagian tersebut dengan pipa |
sehingga output dari find
menjadi input dari while
lingkaran.
Saat Anda menguji kode ini, saya sarankan Anda menambahkan awalan keduanya ffmpeg
dan rm
dengan echo
sehingga Anda dapat melihat apa yang akan dieksekusi – dan dengan jalur apa.
Berikut adalah hasil akhirnya, termasuk echo
pernyataan yang saya rekomendasikan untuk pengujian:
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