¿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?


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

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.


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


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.


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.


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

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.


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.


¿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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.