
Tenho vários arquivos de vídeo com resoluções diferentes. Agora quero listar apenas os nomes dos arquivos de vídeo com, por exemplo, resolução de 720p. Eu prefiro um liner na linha de comando do bash e posso receber informações úteis de vídeo, incluindo resolução, quando executo:
avconv -i video.mp4
mas esta combinação:
find -exec sh -c 'if [[ "$(avconv -i {}") == *720* ]] ; then echo 720 found; fi;'
produz o erro: exec - argumento ausente.
Para ser sincero, quase não brigo com estruturas de comando bash, especialmente comandos combinados. Então, o que há de errado na minha sequência de comandos combinada?
Obrigado.
Responder1
Talvez este comando cumpra o que você está procurando:
for i in *.mp4; do if [[ $(avconv -i $i) =~ .*720.* ]]; then echo $i; fi; done
Responder2
Pode ser surpreendente, mas -exec
pode ser usado como teste na find
invocação:
find -type f -exec sh -c 'ffprobe -show_streams 2>/dev/null "$1" | grep -q coded_height=720' sh {} \; -print
O comando acima descerá para subdiretórios. Para pesquisar apenas no diretório atual use -maxdepth 1
, ou seja:
find -maxdepth 1 -type f -exec …
Observe que isso ffprobe
testará todos os arquivos. Obviamente, falhará em arquivos que não sejam de mídia, mas você poderá obter mídia que não seja de vídeo (como .jpg
) na saída final. Para evitar isso, alguns testes adicionais find
devem ser usados antes -exec
, por exemplo:
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
Ou melhor, você pode testar o tipo MIME com 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
Leia man find
para saber mais.
EDITAR:
Este comando (mal) usa avconv
, conforme você solicitou:
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
O problema é que cada invocação avconv
gera um erro. Nós simplesmente ignoramos e extraímos as informações de que precisamos. Esta é uma solução um tanto feia. Não tenho certeza se você avconv
se comporta como o meu; pode ser necessário substituí-lo Stream.*x720
por algum outro regex.
o que há de errado na minha string de comando combinada?
find -exec
requer fechar com\;
ou+
,existedepois que você editou a pergunta, há$(
sem)
""
intercalação (não aninhada) com$()
,*720*
pode desencadear o globbing do shell, deveria ser"*720*"
(estou falandosh
, não do shell externo),- a saída que
avconv
você tenta analisar vai parastderr
, acho que você precisa redirecioná-la antes de poder analisá-la, - e talvez outra coisa.
Responder3
Não conheço avconv, costumo usar ffmpeg. Se você instalá-lo, você pode 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
Responder4
No momento, encontrei uma solução utilizável:
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
Aqui eu posso fazer um loop em todos os m?? arquivos de vídeo e imprima seu nome incluindo a condição "720". Sem a parte if eu poderia deixar me mostrar todos os vídeos e suas resoluções.
Eu resolvi isso com a ajuda de outras respostas aqui.
Quando tento combinar find e exec e a parte do da solução acima, recebo apenas mensagens "E: Erro de leitura de arquivo" como resultado do mediainfo para cada assunto:
find -exec mediainfo "{}" \; -exec bash -c 'sm=$(mediainfo ${} | grep 720) : ; echo $sm' \;
Como eu disse, a construção 'if' funciona (para o diretório real), mas tentarei fazê-la funcionar com find também.