Mám nápad spustit bash skript ke kontrole některých podmínek a použít ffmpeg převést všechna videa v mém adresáři z libovolného formátu do .mkv a funguje to skvěle!
Jde o to, že jsem nevěděl, že for file in smyčka nefunguje rekurzivně (https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively)
Ale sotva rozumím „potrubím“ a těším se, až uvidím příklad a vyjasním některé nejistoty.
Mám na mysli tento scénář, který by mi podle mě hodně pomohl pochopit.
Předpokládejme, že mám tento fragment bash skriptu:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Co to dělá, je, že pro aktuální adresář vyhledá jakýkoli *.mkv *avi *mp4 *flv *ogg *mov pak deklarujte, že výstup má příponu .mkv poté smažte původní soubor a výstup by měl být uložen do stejné složky, ve které je původní video.
-
Jak to mohu převést, aby běželo rekurzivně? pokud použiji
find, kde deklarovat proměnnou$file? A kde byste měli deklarovat$target? Jsou všechnyfindjen opravdu jednovrstvé? Opravdu potřebuji předat soubor do proměnné$file, protože stále budu muset spustit kontrolu stavu. -
A za předpokladu, že (1) je úspěšná, jak zajistit, aby byl splněn požadavek „výstup by pak měl být uložen do stejné složky, ve které je původní video“?
Přijatá odpověď:
Máte tento kód:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
který běží v aktuálním adresáři. Chcete-li to změnit na rekurzivní proces, máte několik možností. Nejjednodušší (IMO) je použít find jak jsi navrhl. Syntaxe pro find je velmi „un-UNIX-like“, ale principem je, že každý argument lze použít s podmínkami AND nebo OR. Zde řekneme „Pokud se tento název souboru shoduje NEBO se shoduje tento název souboru, pak vytiskni “. Vzory názvů souborů jsou v uvozovkách, aby se k nim shell nemohl dostat (nezapomeňte, že shell je zodpovědný za rozšíření všech neuvedených vzorů, takže pokud jste měli vzor v uvozovkách *.mp4 a měli jste janeeyre.mp4 ve vašem aktuálním adresáři by shell nahradil *.mp4 se shodou a find uvidí -name janeeyre.mp4 místo vašeho požadovaného -name *.mp4; zhorší se to, pokud *.mp4 odpovídá více jménům…). Před závorkami je \ také proto, aby se je shell nepokoušel použít jako značky podslupky (můžeme místo toho citovat závorky, pokud dáváte přednost:'(' ).
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print
Výstup tohoto musí být vložen do vstupu while smyčka, která postupně zpracovává každý soubor:
while IFS= read file ## IFS= prevents "read" stripping whitespace
do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Nyní zbývá pouze spojit dvě části dohromady pomocí trubky | takže výstup find se stane vstupem while smyčka.
Při testování tohoto kódu bych doporučil předponu oběma ffmpeg a rm s echo takže můžete vidět, co by být proveden – a jakými cestami.
Zde je konečný výsledek včetně echo výroky, které doporučuji k testování:
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