GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Konvertieren von „for File In“ in „find“, damit das Skript rekursiv angewendet werden kann?

Ich habe diese Idee, ein Bash-Skript auszuführen, um einige Bedingungen zu überprüfen und ffmpeg zu verwenden um alle Videos in meinem Verzeichnis von jedem Format in .mkv zu konvertieren und es funktioniert großartig!

Die Sache ist, ich wusste nicht, dass ein for file in Schleife funktioniert nicht rekursiv (https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively)

Aber ich verstehe „Piping“ kaum und freue mich darauf, ein Beispiel zu sehen und einige Unklarheiten auszuräumen.

Ich habe dieses Szenario im Sinn, von dem ich denke, dass es mir sehr helfen würde, es zu verstehen.

Angenommen, ich habe dieses Bash-Skript-Snippet:

for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
    ffmpeg -i "$file" "$target" && rm -rf "$file"
done

Was es tut, ist, für das aktuelle Verzeichnis nach *.mkv *avi *mp4 *flv *ogg *mov zu suchen deklarieren Sie dann die Ausgabe mit der Erweiterung .mkv Löschen Sie anschließend die Originaldatei, dann sollte die Ausgabe in demselben Ordner gespeichert werden, in dem sich das Originalvideo befindet.

  1. Wie kann ich dies konvertieren, um rekursiv zu laufen? wenn ich find verwende , wo die Variable $file zu deklarieren ist ? Und wo sollten Sie $target deklarieren ? Sind alle find nur wirklich Einzeiler? Ich muss die Datei wirklich an eine Variable $file übergeben , da ich die Bedingungsprüfung noch ausführen muss.

  2. Und unter der Annahme, dass (1) erfolgreich ist, wie kann sichergestellt werden, dass die Anforderung „dann sollte die Ausgabe in demselben Ordner gespeichert werden, in dem sich das Originalvideo befindet“ erfüllt ist?

Akzeptierte Antwort:

Sie haben diesen Code:

for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
    ffmpeg -i "$file" "$target" && rm -rf "$file"
done

die im aktuellen Verzeichnis läuft. Um es in einen rekursiven Prozess umzuwandeln, haben Sie ein paar Möglichkeiten. Am einfachsten (IMO) ist die Verwendung von find wie du vorgeschlagen hast. Die Syntax für find ist sehr „UNIX-unähnlich“, aber das Prinzip hier ist, dass jedes Argument mit UND- oder ODER-Bedingungen angewendet werden kann. Hier sagen wir „Wenn dieser Dateiname übereinstimmt ODER dieser Dateiname übereinstimmt, dann drucken Sie es aus.“ “. Die Dateinamenmuster werden in Anführungszeichen gesetzt, damit die Shell sie nicht finden kann (denken Sie daran, dass die Shell für das Erweitern aller Muster ohne Anführungszeichen verantwortlich ist, wenn Sie also ein Muster ohne Anführungszeichen von *.mp4 hätten und Sie hatten janeeyre.mp4 in Ihrem aktuellen Verzeichnis würde die Shell *.mp4 ersetzen mit der Übereinstimmung und find würde -name janeeyre.mp4 sehen anstelle Ihres gewünschten -name *.mp4; schlimmer wird es, wenn *.mp4 stimmt mit mehreren Namen überein…). Den Klammern wird \ vorangestellt auch um zu verhindern, dass die Shell versucht, sie als Subshell-Marker zu verwenden (wir könnten stattdessen die Klammern zitieren, wenn dies bevorzugt wird:'(' ).

find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print

Die Ausgabe davon muss in die Eingabe von while eingespeist werden Schleife, die jede Datei der Reihe nach verarbeitet:

while IFS= read file    ## IFS= prevents "read" stripping whitespace
do
    target="${file%.*}.mkv"
    ffmpeg -i "$file" "$target" && rm -rf "$file"
done

Jetzt müssen die beiden Teile nur noch mit einer Pipe | verbunden werden damit die Ausgabe von find wird zur Eingabe von while Schleife.

Verwandte Themen:Kann CloudMagic den Inhalt einer Datei in Dropbox durchsuchen?

Während Sie diesen Code testen, empfehle ich Ihnen, beiden ffmpeg voranzustellen und rm mit echo damit Sie sehen können, was würde ausgeführt werden – und mit welchen Pfaden.

Hier ist das Endergebnis, einschließlich des echo Anweisungen, die ich zum Testen empfehle:

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. 8 gruselige Befehle, die das Terminal heimsuchen

  2. So finden Sie das Paket, das eine bestimmte Datei in Linux bereitstellt

  3. Warum erkennt das Bash-Skript keine Aliase?

  4. Wenn ich Berechtigungen für eine Tar-Datei ändere, gilt das für die darin enthaltenen Dateien?

  5. Alle Terminalausgaben in einer Datei speichern?

Wie vermeidet ein Shell-Skript die Sigpipe, die durch die Verwendung eines geschlossenen Dateideskriptors verursacht würde?

Gibt es eine Qt-Installationspfadvariable, die ich in der .pro-Datei verwenden kann?

Wie kann ich Dateien rekursiv nach Dateierweiterung kopieren und dabei die Verzeichnisstruktur beibehalten?

Wie kann ich den Dateiinhalt rekursiv anzeigen?

Wie finde ich die älteste Datei in einem Verzeichnisbaum?

Kann der Init-Prozess ein Shell-Skript in Linux sein?