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šechnyfind
jen 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