Ho questa idea di eseguire uno script bash per verificare alcune condizioni e utilizzare ffmpeg
per convertire tutti i video nella mia directory da qualsiasi formato in .mkv
e funziona benissimo!
Il fatto è che non sapevo che un for file in
loop non funziona in modo ricorsivo (https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively)
Ma capisco a malapena il "piping" e non vedo l'ora di vedere un esempio e chiarire alcune incertezze.
Ho in mente questo scenario che penso mi aiuterebbe molto a capire.
Supponiamo che io abbia questo frammento di script bash:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Quello che fa è, per la directory corrente, cercare qualsiasi *.mkv *avi *mp4 *flv *ogg *mov
quindi dichiara che l'output ha l'estensione .mkv
quindi in seguito elimina il file originale, quindi l'output dovrebbe essere salvato nella stessa cartella in cui si trova il video originale.
-
Come posso convertirlo in modo che venga eseguito in modo ricorsivo? se uso
find
, dove dichiarare la variabile$file
? E dove dovresti dichiarare$target
? Sono tuttifind
davvero solo battute? Ho davvero bisogno di passare il file a una variabile$file
, perché dovrò comunque eseguire il controllo delle condizioni. -
E, supponendo che (1) abbia esito positivo, come assicurarsi che il requisito "quindi l'output dovrebbe essere salvato nella stessa cartella in cui si trova il video originale" sia soddisfatto?
Risposta accettata:
Hai questo codice:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
che viene eseguito nella directory corrente. Per trasformarlo in un processo ricorsivo hai un paio di scelte. Il più semplice (IMO) è usare find
come hai suggerito. La sintassi per find
è molto "non simile a UNIX", ma il principio qui è che ogni argomento può essere applicato con condizioni AND o OR. Qui diremo "Se questo-nome-file corrisponde OPPURE quel-nome-file corrisponde, allora stampalo “. I pattern dei nomi dei file sono citati in modo che la shell non possa ottenerli (ricorda che la shell è responsabile dell'espansione di tutti i pattern non tra virgolette, quindi se avessi un pattern non tra virgolette di *.mp4
e avevi janeeyre.mp4
nella tua directory corrente, la shell sostituirà *.mp4
con la corrispondenza e find
vedrebbe -name janeeyre.mp4
invece del -name *.mp4
desiderato; peggiora se *.mp4
corrisponde a più nomi…). Le parentesi sono precedute da \
anche per evitare che la shell tenti di utilizzarli come indicatori di sottoshell (potremmo invece citare le parentesi, se si preferisce:'('
).
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print
L'output di questo deve essere inserito nell'input di un while
loop che elabora ogni file a turno:
while IFS= read file ## IFS= prevents "read" stripping whitespace
do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Ora non resta che unire le due parti insieme con una pipe |
in modo che l'output di find
diventa l'input del while
ciclo.
Mentre stai testando questo codice, ti consiglio di anteporre entrambi ffmpeg
e rm
con echo
così puoi vedere cosa sarebbe essere eseguito – e con quali percorsi.
Ecco il risultato finale, incluso echo
affermazioni che consiglio per il test:
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