Linux: как составить список всех видеофайлов с разрешением точно 720p?

Linux: как составить список всех видеофайлов с разрешением точно 720p?

У меня есть несколько видеофайлов с разным разрешением. Теперь я хочу перечислить только имена видеофайлов с разрешением, например, 720p. Я предпочитаю однострочные команды в командной строке bash и могу получить полезную информацию о видео, включая разрешение, когда выполняю:

avconv -i video.mp4

но эта комбинация:

find -exec sh -c 'if [[ "$(avconv -i {}") == *720* ]] ; then echo 720 found; fi;'

выдает ошибку: exec - отсутствует аргумент.

Честно говоря, я почти не сталкивался со структурами команд bash, особенно с комбинированными командами. Так что же не так в моей комбинированной командной строке?

Спасибо.

решение1

Возможно, эта команда выполняет то, что вы ищете:

for i in *.mp4; do if [[ $(avconv -i $i) =~ .*720.* ]]; then echo $i; fi; done

решение2

Это может показаться удивительным, но -execможет использоваться в качестве теста при findвызове:

find -type f -exec sh -c 'ffprobe -show_streams 2>/dev/null "$1" | grep -q coded_height=720' sh {} \; -print

Вышеуказанная команда спустится в подкаталоги. Для поиска только в текущем каталоге используйте -maxdepth 1, то есть:

find -maxdepth 1 -type f -exec …

Обратите внимание, что это ffprobeбудет проверять все файлы. Очевидно, что это не будет работать для файлов, не являющихся медиа, но вы можете получить не видео медиа (например, .jpg) в конечном выводе. Чтобы избежать этого, некоторые дополнительные тесты findдолжны быть использованы перед -exec, например:

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

Или лучше вы можете проверить тип MIME с помощью 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

Прочтите man find, чтобы узнать больше.


РЕДАКТИРОВАТЬ:

Эта команда (неправильно) использует avconv, как вы и просили:

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

Проблема в том, что каждый вызов avconvtherein выдает ошибку. Мы просто игнорируем ее и извлекаем нужную нам информацию. Это довольно уродливое решение. Я не совсем уверен, что ваше avconvведет себя так же, как мое, возможно, вам нужно заменить его Stream.*x720на какое-то другое регулярное выражение.


что не так в моей объединенной командной строке?

  • find -execтребуется закрытие с помощью \;или +,
  • есть $(без) после того, как вы отредактировали вопрос, там ""чередуются (не вложены) с $(),
  • *720*может вызвать подстановку оболочки, должно быть "*720*"(я говорю о sh, а не о внешней оболочке),
  • вывод avconvвашей попытки проанализировать идет в stderr, я думаю, вам нужно перенаправить его, прежде чем вы сможете его проанализировать,
  • и, возможно, что-то еще.

решение3

Я не знаю avconv, я обычно использую ffmpeg. Если вы установите его, вы можете использовать этот скрипт

#!/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

решение4

На данный момент я нашел приемлемое решение:

 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

Здесь я могу зациклить все m?? видеофайлы и вывести их имя, включая условие "720". Без части if я мог бы позволить мне показывать все видео и их разрешения.

Я разобрался в этом с помощью других ответов здесь.

Когда я пытаюсь объединить find и exec с частью do из приведенного выше решения, я получаю только сообщения «E: Ошибка чтения файла» в качестве результата от mediainfo для каждой темы:

 find -exec mediainfo "{}" \; -exec bash -c 'sm=$(mediainfo ${} | grep 720) : ; echo $sm' \;

Как я уже сказал, конструкция «if» работает (для фактического каталога), но я попробую заставить ее работать и с find.

Связанный контент