GNU/Linux >> Linux Esercitazione >  >> Linux

Conversione di "per file in" in "trova" in modo che lo script possa essere applicato in modo ricorsivo?

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.

  1. 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 tutti find davvero solo battute? Ho davvero bisogno di passare il file a una variabile $file , perché dovrò comunque eseguire il controllo delle condizioni.

  2. 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.

Correlati:CloudMagic può cercare il contenuto di un file in Dropbox?

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

Linux
  1. Come trovare il pacchetto che fornisce un file specifico in Linux

  2. Perché lo script Bash non riconosce gli alias?

  3. Script Bash per rimuovere il file più vecchio da una cartella?

  4. Non riesci a ottenere il codice di uscita corretto da uno script?

  5. In che modo uno script di shell evita il Sigpipe che sarebbe causato dall'uso di un descrittore di file chiuso?

Se cambio le autorizzazioni su un file tar, si applicherà ai file al suo interno?

Salva tutto l'output del terminale in un file?

Variabile in Bash Script che mantiene il valore dall'ultima esecuzione

Esiste una variabile del percorso di installazione di Qt che posso utilizzare nel file .pro?

Un file .sh può essere un malware?

Il processo init può essere uno script di shell in Linux?