Come posso usare due parametri contemporaneamente con xargs?


18

Devo convertire i video, ma non so dove siano, quindi ho bisogno di findloro. Come posso assegnare il risultato e il nome di un file di output a FFmpeg con xargs?

Ho già scoperto che posso costruire i due parametri con questo comando:

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

Non riesco a trovare nulla di correlato nel xargsmanuale. Voglio qualcosa del genere:

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

Come posso fare questo?


Quelli di voi che si imbattono in questa domanda perché state cercando una risposta su più argomenti con xargs in generale potrebbero voler controllare stackoverflow.com/questions/3770432/… .
Chris Oldwood,

Risposte:


4

Qualcosa del genere farà il trucco e manterrà il percorso completo, gestirà lo spazio, rinominerà folder/movie.movin folder/movie.flv, ecc.

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

E se ti ho frainteso e vuoi tutti i film .flv nella directory corrente, usa invece questo:

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

3
Se lo vuoi come oneliner, basta mettere tutto su una linea. ;)
Mattias Ahnberg

9

Il motivo per cui le persone usano xargsin combinazione con find è che più nomi di file verranno passati allo stesso richiamo del programma di qualunque programma venga xargsavviato. Ad esempio, se findrestituisce i file foo , bar e baz , quanto segue verrà eseguito mvuna sola volta:

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

In effetti, chiama mvcome il seguente:

mv -t destDir foo bar baz

Se non avete bisogno o volete questo comportamento (come presumo sia il caso qui), si può semplicemente utilizzare finds' -exec.


In questo caso, una soluzione semplice sarebbe quella di scrivere uno script di shell corta, come il seguente:

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

Salva come myffmpeg.shed esegui chmod +x myffmpeg.sh. Quindi, esegui quanto segue:

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

Questo invocherà lo script della shell una volta per ogni file trovato. Lo script shell a sua volta estrae il nome del file dal percorso completo e chiama ffmpegcon gli argomenti appropriati.


4

Non ho ottenuto la soluzione che mi aspettavo, quindi ho scoperto la mia. @La risposta di Daniel è buona, ma ha bisogno di uno script di shell. Una riga è più veloce e mi piace di più :) soluzione anche più semplice rispetto alla scrittura di una sceneggiatura.

Potrei usare un argomento ed elaborarlo con basenamee usandosh -c

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

-I dice a xargs di sostituire {}con l'argomento corrente.
L'output del comando all'interno di `` stampato sull'output standard (funzione bash) basename {}verrà quindi valutato come il nome del file nudo e stampato.
-0 per gestire correttamente nomi di file speciali, ma è necessario passare i parametri con l'opzione -print0 con find


3

Devi farlo come tutte le risposte lassù, ma l'uso ESATTO di xargs sarà qualcosa del genere:

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

Quindi nel tuo caso sarà:

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

PS: Questo risponde alla domanda su xargs per coloro che cercano una risposta esattamente per più xargsparametri in un solo xargscomando.


1

Perché non spostare semplicemente le opzioni di ffmpeg per adattarle al formato dei risultati dal comando find ?

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

Notare l'aggiunta dell'opzione -r a xargs per impedire l'esecuzione di ffmpeg se non viene trovato alcun file .mov .

Ho aggiunto l' opzione -n2 a xargs per limitare il numero di elementi processi xargs alla volta. In questo caso, gli elementi sono il percorso del file e il nome del file. Se non è impostata alcuna opzione -n , xargs elaborerà il maggior numero possibile di elementi di input in un'unica esecuzione.


Questo non funzionerà una volta trovato più di un file AFAICT.
Daniel Beck

Questo funziona solo una volta anche per me, ma non capisco perché si interrompa dopo il primo. Qualche idea ?
kissgyorgy,

in realtà non funziona
kissgyorgy

Daniel-Beck e @Walkman avevano ragione sulla singola esecuzione. Per risolvere questo problema, ho modificato questa risposta per limitare il numero di elementi che xargs elabora alla volta tramite l' opzione -n2 . Senza -n2 , xargs viene eseguito una sola volta se è in grado di gestire il numero di elementi di input che riceve attraverso la pipe. Va inoltre sottolineato che questa soluzione funziona solo quando i nomi dei file e i percorsi dei file non includono spazi bianchi.
ZaSter

1

Non sono sicuro se puoi o come farlo con xargs.

Ma qualcosa del genere dovrebbe funzionare per te:

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done

1
Questo non gestisce correttamente gli spazi nei nomi / percorsi dei file, vero?
Daniel Beck

1

Un'alternativa alla risposta di Zoredache usando l'associazione dei nomi (e usando diversi separatori per evitare il problema degli spazi nei nomi dei file):

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

Ovviamente puoi anche usare i separatori con l' find -a arrayargomento usato dall'altra risposta, ma a volte argomenti più chiari sono più comprensibili.


0

Puoi eseguire ffmpeg direttamente dal comando find in questo modo:

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

Nota le virgolette attorno ai parametri su ffmpeg, nel caso in cui vi siano spazi nel nome del file e il punto e virgola sfuggito segna la fine del comando eseguito.


Hai documentazione per il comportamento di -exec che interpreta anche i segnaposto di formattazione di printf?
Daniel Beck

No. Brain scoreggia: stavo pensando che% p e% f fossero cose da trovare, non cose da stampare. Ho votato per la tua risposta.
Randy Orrison,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.