¿Cómo puedo usar dos parámetros a la vez con xargs?

18

Necesito convertir videos, pero no sé dónde están, así que los necesito find. ¿Cómo puedo dar el resultado y un nombre de archivo de salida para FFmpeg con xargs?

Ya descubrí que puedo construir los dos parámetros con este comando:

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

No puedo encontrar nada relacionado en el xargsmanual. Quiero algo como esto:

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

¿Cómo puedo hacer esto?

kissgyorgy
fuente
Aquellos de ustedes que se encuentran con esta pregunta porque están buscando una respuesta sobre múltiples argumentos con, xargs en general, pueden consultar stackoverflow.com/questions/3770432/… .
Chris Oldwood

Respuestas:

4

Algo como esto hará el truco y preservar la ruta completa, espacio de mango, de cambio de nombre folder/movie.mova folder/movie.flv, etc.

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

Y si te entendí mal y quieres todas las películas .flv en el directorio actual, usa esta en su lugar:

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "$(basename "${movie%.mov}.flv")"
done
Mattias Ahnberg
fuente
3
Si lo quieres como línea, pon todo en una línea. ;)
Mattias Ahnberg
9

La razón por la que las personas usan xargsen combinación con find es que se pasarán varios nombres de archivo a la misma invocación de programa de cualquier programa que se xargsinicie. Por ejemplo, si finddevuelve los archivos foo , bar y baz , lo siguiente se ejecutará mvsolo una vez:

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

Efectivamente, se llama mvasí:

mv -t destDir foo bar baz

Si no necesita o desea este comportamiento (como supongo que es el caso aquí), simplemente puede usar find's -exec.


En este caso, una solución fácil sería escribir un script de shell corto, como el siguiente:

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

Guardar como myffmpeg.shy correr chmod +x myffmpeg.sh. Luego, ejecute lo siguiente:

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

Esto invocará el script de shell una vez por cada archivo encontrado. El script de shell a su vez extrae el nombre del archivo de la ruta completa y llama ffmpegcon los argumentos apropiados.

Daniel Beck
fuente
4

No obtuve la solución que esperaba, así que descubrí la mía. @ La respuesta de Daniel es buena, pero necesita un script de shell. Un one liner es más rápido, y me gusta más :) también es una solución más simple que escribir un script.

Podría usar un argumento y procesarlo con basenamey usandosh -c

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

El -i le dice a xargs que lo reemplace {}con el argumento actual.
La salida del comando dentro de `` se imprime en la salida estándar (función bash), por basename {}lo que se evaluará como el nombre del archivo sin formato y se imprimirá.
-0 para manejar nombres de archivos especiales correctamente, pero necesita pasar parámetros con la opción -print0 con find

kissgyorgy
fuente
3

Tienes que hacerlo como todas las respuestas, pero el uso EXACTO de xargs será algo como esto:

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

Entonces en tu caso será:

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

PD: Esto responde la pregunta sobre xargs para aquellos que buscan una respuesta exactamente para múltiples xargsparámetros en un xargscomando.

sauliux zyziux
fuente
1

¿Por qué no simplemente mover las opciones de ffmpeg para que se ajusten al formato de los resultados del comando find ?

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

Observe la adición de la opción -r a xargs para evitar que ejecute ffmpeg si no se encuentran archivos .mov .

He agregado la opción -n2 a xargs para limitar la cantidad de elementos que xargs procesa a dos a la vez. En este caso, los elementos son la ruta del archivo y el nombre del archivo. Si no se establece la opción -n , xargs procesará tantos elementos de entrada como sea posible en una sola ejecución.

ZaSter
fuente
Esto no funcionará una vez que se encuentre más de un archivo AFAICT.
Daniel Beck
Esto también funciona solo una vez para mí, pero no entiendo por qué se detiene después del primero. Alguna idea ?
kissgyorgy
en realidad no funciona
kissgyorgy
Daniel-Beck y @Walkman tenían razón sobre la ejecución individual. Para resolver ese problema, he editado esta respuesta para limitar el número de elementos que xargs procesa a la vez a través de la opción -n2 . Sin la -n2 , xargs se ejecuta sólo una vez si puede manejar el número de elementos de entrada que recibe a través de la tubería. También debe señalarse que esta solución solo funciona cuando los nombres y las rutas de los archivos no incluyen espacios en blanco.
ZaSter
1

No estoy seguro de si puedes o cómo hacerlo con xargs.

Pero algo como esto debería funcionar para usted:

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done
Zoredache
fuente
1
Esto no maneja correctamente los espacios en los nombres de archivo / rutas, ¿verdad?
Daniel Beck
1

Una alternativa a la respuesta de Zoredache usando el enlace de nombre (y usando diferentes separadores para evitar el problema de espacios en los nombres de archivo):

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

Por supuesto, también puede usar los separadores con el find -a arrayargumento que había usado la otra respuesta, pero a veces los argumentos nombrados son más comprensibles.

wolf1oo
fuente
0

Puede ejecutar ffmpeg directamente desde el comando find como este:

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

Tenga en cuenta las comillas alrededor de los parámetros para ffmpeg, en caso de que haya espacios en el nombre del archivo, y el punto y coma escapado marca el final del comando ejecutado.

Randy Orrison
fuente
¿Tiene documentación para el comportamiento de -exec que también interpreta los marcadores de posición de formato printf?
Daniel Beck
No Pedo cerebral: estaba pensando que% p y% f eran cosas de búsqueda, no cosas de impresión. He votado tu respuesta.
Randy Orrison