
У меня есть несколько видеофайлов с разным разрешением. Теперь я хочу перечислить только имена видеофайлов с разрешением, например, 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
Проблема в том, что каждый вызов avconv
therein выдает ошибку. Мы просто игнорируем ее и извлекаем нужную нам информацию. Это довольно уродливое решение. Я не совсем уверен, что ваше 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.