
Tengo varios archivos de video con diferentes resoluciones. Ahora quiero enumerar sólo los nombres de archivos de vídeo con, por ejemplo, una resolución de 720p. Prefiero una línea en la línea de comando de bash y puedo recibir información de video útil, incluida la resolución, cuando ejecuto:
avconv -i video.mp4
pero esta combinación:
find -exec sh -c 'if [[ "$(avconv -i {}") == *720* ]] ; then echo 720 found; fi;'
produce el error: ejecutivo: falta argumento.
Soy honesto, apenas tengo peleas con las estructuras de comando de bash, especialmente con los comandos combinados. Entonces, ¿qué hay de malo en mi cadena de comando combinada?
Gracias.
Respuesta1
Quizás este comando logre lo que buscas:
for i in *.mp4; do if [[ $(avconv -i $i) =~ .*720.* ]]; then echo $i; fi; done
Respuesta2
Puede resultar sorprendente, pero -exec
se puede utilizar como prueba en find
la invocación:
find -type f -exec sh -c 'ffprobe -show_streams 2>/dev/null "$1" | grep -q coded_height=720' sh {} \; -print
El comando anterior descenderá a los subdirectorios. Para buscar en el directorio actual utilice únicamente -maxdepth 1
, es decir:
find -maxdepth 1 -type f -exec …
Tenga en cuenta que ffprobe
probará todos los archivos. Obviamente fallará con archivos que no sean multimedia, pero es posible que obtenga medios que no sean de video (como .jpg
) en la salida final. Para evitar esto, find
se deben realizar algunas pruebas adicionales antes -exec
, por ejemplo:
find -maxdepth 1 -type f \( -iname "*.avi" -o -iname "*.mp4" -o -iname "*.mkv" \) -exec sh -c 'ffprobe -show_streams 2>/dev/null "$1" | grep -q coded_height=720' sh {} \; -print
O mejor, puedes probar el tipo mime con file
:
find -maxdepth 1 -exec sh -c 'file --mime-type "$1" | grep -q "video/"' sh {} \; -exec sh -c 'ffprobe -show_streams 2>/dev/null "$1" | grep -q coded_height=720' sh {} \; -print
Lea man find
para obtener más información.
EDITAR:
Este comando usa (mal) avconv
, como usted solicitó:
find -exec sh -c 'file --mime-type "$1" | grep -q "video/"' sh {} \; -exec sh -c 'avconv 2>&1 -i "$1" | grep -q "Stream.*x720"' sh {} \; -print
El problema es que cada invocación del avconv
mismo arroja un error. Simplemente lo ignoramos y extraemos la información que necesitamos. Esta es una solución algo fea. No estoy del todo seguro de que avconv
se comporte como el mío, es posible que deba reemplazarlo Stream.*x720
con alguna otra expresión regular.
¿Qué hay de malo en mi cadena de comando combinada?
find -exec
requiere cerrar con\;
o+
,haydespués de editar la pregunta, están$(
sin)
""
intercalados (no anidados) con$()
,*720*
puede desencadenar el globalización de la capa, debería ser"*720*"
(estoy hablando desh
, no de la capa exterior),- el resultado de
avconv
tu intento de analizar va astderr
, creo que necesitas redirigirlo antes de poder analizarlo. - y tal vez algo más.
Respuesta3
No conozco avconv, normalmente uso ffmpeg. Si lo instalas podrías usar este script.
#!/bin/bash
OIFS="$IFS"
IFS=$'\n'
files=$(find ./ -type f -exec ls {} + | grep ".*\.mpg$\|.*\.avi$\|.*\.mkv$\|.*\.mp4$"| cut -c3-)
for f in ${files}
do
resolution=$(ffprobe -v error -select_streams v:0 -show_entries
stream=height -of csv=s=x:p=0 ${f})
printf "%-100s %-10s\n" $f $resolution
done
Respuesta4
Por el momento he encontrado una solución utilizable:
for i in ls *.m??; do sm=$(mediainfo $i | grep Height | sed 's/ //g');if [[ "$sm" == *720* ]]; then printf "Video: %-s $i %-s $sm \n"; fi; done
¿Aquí puedo repetir todos los m? archivos de vídeo e imprima su nombre, incluida la condición "720". Sin la parte if podría mostrarme todos los videos y sus resoluciones.
Resolví esto con la ayuda de otras respuestas aquí.
Cuando intento combinar find y exec y la parte do de la solución anterior, solo recibo mensajes "E: Error de lectura de archivo" como resultado de mediainfo para cada tema:
find -exec mediainfo "{}" \; -exec bash -c 'sm=$(mediainfo ${} | grep 720) : ; echo $sm' \;
Como dije, la construcción 'si' funciona (para el directorio real), pero intentaré ejecutarla también con buscar.