Wie kann ich mit xargs zwei Parameter gleichzeitig verwenden?

18

Ich muss Videos konvertieren, aber ich weiß nicht, wo sie sind, also brauche ich findsie. Wie kann ich FFmpeg mit dem Ergebnis und einem Ausgabedateinamen versehen xargs?

Ich habe bereits herausgefunden, dass ich mit diesem Befehl die beiden Parameter konstruieren kann:

find . -iname "*.mov" -printf "%p %f\n"

Ich kann nichts im xargsHandbuch finden. Ich möchte so etwas:

find . -iname "*.mov" -printf "%p %f\n" | xargs ffmpeg -i {param1} -f flv {param2}

Wie kann ich das machen?

kissgyorgy
quelle
Diejenigen von Ihnen, die über diese Frage stolpern, weil Sie nach einer Antwort zu mehreren Argumenten mit xargs im Allgemeinen suchen, möchten vielleicht stackoverflow.com/questions/3770432/… .
Chris Oldwood

Antworten:

4

So etwas erledigt den Trick und erhält den vollständigen Pfad, behandelt den Speicherplatz, benennt ihn folder/movie.movum folder/movie.flvin usw.

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "${movie%.mov}.flv"
done

Und wenn ich Sie missverstanden habe und Sie alle .flv-Filme im aktuellen Verzeichnis haben möchten, verwenden Sie stattdessen dieses:

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "$(basename "${movie%.mov}.flv")"
done
Mattias Ahnberg
quelle
3
Wenn Sie es als Oneliner wollen, setzen Sie einfach alles in eine Zeile. ;)
Mattias Ahnberg
9

Der Grund, den die Benutzer xargsin Kombination mit find verwenden, besteht darin, dass bei jedem Programmstart mehrere Dateinamen an denselben Programmaufruf übergeben werden xargs. Wenn beispielsweise finddie Dateien foo , bar und baz zurückgegeben werden , wird Folgendes mvnur einmal ausgeführt:

find sourceDir [...] -print0 | xargs -0 mv -t destDir

Tatsächlich lautet der Aufruf mvwie folgt:

mv -t destDir foo bar baz

Wenn Sie dieses Verhalten nicht benötigen oder wollen (wie ich hier annehme), können Sie einfach find's verwenden -exec.


In diesem Fall besteht eine einfache Lösung darin, ein kurzes Shell-Skript wie das folgende zu schreiben:

#!/usr/bin/env bash
[[ -f "$1" ]] || { echo "$1 not found" ; exit 1 ; }
P="$1"
F="$( basename $P )"
ffmpeg -i "$P" -f flv "$F"

Speichern unter myffmpeg.shund ausführen chmod +x myffmpeg.sh. Führen Sie dann Folgendes aus:

find . -iname "*.mov" -exec /path/to/myffmpeg.sh {} \;

Dadurch wird das Shell-Skript für jede gefundene Datei einmal aufgerufen. Das Shell-Skript extrahiert wiederum den Dateinamen aus dem vollständigen Pfad und ruft ffmpegmit den entsprechenden Argumenten auf.

Daniel Beck
quelle
4

Ich habe nicht die Lösung bekommen, die ich erwartet hatte, also habe ich meine eigene herausgefunden. @ Daniels Antwort ist gut, aber es braucht ein Shell-Skript. Ein Einzeiler ist schneller, und ich mag es besser :) auch einfachere Lösung als das Schreiben eines Skripts.

Ich könnte ein Argument verwenden und es mit basenameund mit verarbeitensh -c

find . -iname "*.mov" -print0 | xargs -0 -i sh -c 'ffmpeg -i {} -f flv `basename {}`'

Das -i weist xargs an, es {}durch das aktuelle Argument zu ersetzen .
Die Befehlsausgabe innerhalb von `` wird als Standardausgabe (Bash-Funktion) basename {}ausgedruckt und als Dateiname ausgewertet und ausgedruckt.
-0 für die korrekte Behandlung spezieller Dateinamen, aber Sie müssen Parameter mit der Option -print0 mit find übergeben

kissgyorgy
quelle
3

Sie müssen es wie alle Antworten dort oben tun, aber die GENAUE Verwendung von xargs wird ungefähr so ​​aussehen:

echo argument1 argument2 argument3 | xargs -l bash -c 'echo this is first:$0 second:$1 third:$2' | xargs

In Ihrem Fall ist es also:

find . -iname "*.mov" -printf "%p %f\n" | xargs -l bash -c 'echo ffmpeg -i $0 -f flv $1' | xargs

PS: Dies beantwortet die Frage nach xargs für diejenigen, die genau nach einer Antwort für mehrere xargsParameter in einem xargsBefehl suchen .

sauliux zyziux
quelle
1

Warum verschieben Sie nicht einfach die Optionen des ffmpeg , um sie an das Format der Ergebnisse des Befehls find anzupassen?

find . -iname "*.mov" -printf "%p %f\n" | xargs -r -n2 ffmpeg -f flv -i

Beachten Sie das Hinzufügen der Option -r zu xargs , um zu verhindern, dass ffmpeg ausgeführt wird, wenn keine MOV- Dateien gefunden werden.

Ich habe xargs die Option -n2 hinzugefügt , um die Anzahl der xargs- Prozesse auf zwei zu beschränken. In diesem Fall sind die Elemente der Dateipfad und der Dateiname. Wenn keine Option -n festgelegt ist, verarbeitet xargs so viele Eingabeelemente wie möglich in einer einzigen Ausführung.

ZaSter
quelle
Dies funktioniert nicht, wenn mehr als eine Datei gefunden wurde.
Daniel Beck
Dies funktioniert nur einmal für mich auch, aber ich verstehe nicht, warum es nach dem ersten stoppt. Irgendeine Idee ?
Kissgyorgy
Eigentlich funktioniert es nicht
Kissgyorgy
Daniel-Beck und @Walkman waren in Bezug auf die Einzelexekution korrekt. Um dieses Problem zu lösen, habe ich diese Antwort überarbeitet, um die Anzahl der Elemente zu begrenzen, die xargs gleichzeitig verarbeitet. Verwenden Sie dazu die Option -n2 . Ohne -n2 wird xargs nur einmal ausgeführt, wenn es die Anzahl der über die Pipe empfangenen Eingabeelemente verarbeiten kann. Es sollte auch darauf hingewiesen werden, dass diese Lösung nur funktioniert, wenn Dateinamen und Dateipfade keine Leerzeichen enthalten.
ZaSter
1

Ich bin mir nicht sicher, ob du das kannst oder wie du das mit xargs machst.

Aber so etwas sollte für Sie funktionieren:

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done
Zoredache
quelle
1
Dies behandelt Leerzeichen in Dateinamen / -pfaden nicht richtig, oder?
Daniel Beck
1

Eine Alternative zu Zoredaches Antwort mithilfe der Namensbindung (und mithilfe verschiedener Trennzeichen, um Leerzeichen in Dateinamen zu vermeiden):

IFS="\t" find -iname "*.mov" -printf "%p\t%f\n" | while read path file; do
    ffmpeg -i $path -f flv $file
done

Natürlich können Sie die Trennzeichen auch mit dem find -a arrayArgument verwenden, das die andere Antwort verwendet hat, aber manchmal sind benannte Argumente verständlicher.

wolf1oo
quelle
0

Sie können ffmpeg direkt über den Befehl find wie folgt ausführen:

find . -iname "*.mov" -exec ffmpeg -i "%p" -f flv "%f" \;

Beachten Sie die Anführungszeichen um die Parameter für ffmpeg, falls der Dateiname Leerzeichen enthält und das Semikolon das Ende des ausgeführten Befehls markiert.

Randy Orrison
quelle
Haben Sie Dokumentation für das Verhalten von -exec, das auch Platzhalter für die printf-Formatierung interpretiert?
Daniel Beck
Nee. Gehirn-Furz: Ich dachte,% p und% f wären Fundstücke, keine Printstücke. Ich habe für deine Antwort gestimmt.
Randy Orrison