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 tuttifinddavvero 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