Tengo esta idea de ejecutar un script bash para verificar algunas condiciones y usar ffmpeg
para convertir todos los videos en mi directorio de cualquier formato a .mkv
¡y está funcionando muy bien!
El caso es que no sabía que un for file in
loop no funciona recursivamente (https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively)
Pero apenas entiendo "tuberías" y espero ver un ejemplo y aclarar algunas dudas.
Tengo este escenario en mente que creo que me ayudaría mucho a entender.
Supongamos que tengo este fragmento de script bash:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Lo que hace es, para el directorio actual, buscar cualquier *.mkv *avi *mp4 *flv *ogg *mov
luego declare la salida para que su extensión sea .mkv
luego, elimine el archivo original, luego la salida debe guardarse en la misma carpeta en la que se encuentra el video original.
-
¿Cómo puedo convertir esto para que se ejecute recursivamente? si uso
find
, donde declarar la variable$file
? ¿Y dónde deberías declarar$target
? ? Son todosfind
¿realmente frases ingeniosas? Realmente necesito pasar el archivo a una variable$file
, porque aún tendré que ejecutar la verificación de condición. -
Y, suponiendo que (1) tenga éxito, ¿cómo asegurarse de que se cumpla el requisito "entonces la salida debe guardarse en la misma carpeta en la que se encuentra el video original"?
Respuesta aceptada:
Tienes este código:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
que se ejecuta en el directorio actual. Para convertirlo en un proceso recursivo, tiene un par de opciones. El más fácil (IMO) es usar find
como sugeriste. La sintaxis para find
es muy "no similar a UNIX", pero el principio aquí es que cada argumento se puede aplicar con condiciones AND u OR. Aquí, vamos a decir "Si este nombre de archivo coincide O ese nombre de archivo coincide, entonces imprímalo “. Los patrones de nombre de archivo están entrecomillados para que el shell no pueda controlarlos (recuerde que el shell es responsable de expandir todos los patrones sin comillas, por lo que si tenía un patrón sin comillas de *.mp4
y tenías janeeyre.mp4
en su directorio actual, el shell reemplazaría *.mp4
con la coincidencia y find
vería -name janeeyre.mp4
en lugar de su -name *.mp4
; empeora si *.mp4
coincide con varios nombres...). Los corchetes tienen el prefijo \
también para evitar que el shell intente activarlos como marcadores de subshell (podríamos citar los corchetes en su lugar, si lo prefiere:'('
).
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print
La salida de esto debe alimentarse a la entrada de un while
bucle que procesa cada archivo a su vez:
while IFS= read file ## IFS= prevents "read" stripping whitespace
do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Ahora todo lo que queda es unir las dos partes con un tubo |
para que la salida de find
se convierte en la entrada del while
bucle.
Mientras prueba este código, le recomiendo que prefije ambos ffmpeg
y rm
con echo
para que pueda ver lo que sería ser ejecutado – y con qué caminos.
Aquí está el resultado final, incluido el echo
declaraciones que recomiendo para probar:
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