Ffmpeg в трубе bash

У меня есть список путей к файлу rmvb и вы хотите преобразовать эти файлы в файлы mp4. Поэтому я надеюсь использовать конвейер bash для его обработки. Код

Convert() {
    ffmpeg -i "$1" -vcodec mpeg4 -sameq -acodec aac -strict experimental "$1.mp4"
}

Convert_loop(){
    while read line; do
       Convert $line
    done
}

cat list.txt | Convert_loop

Однако он обрабатывает только первый файл, и труба выходит.

Итак, ffmpeg влияет на канал bash?

Ответ 1

Предостережение: я никогда не использовал ffmpeg, но при работе с другими вопросами, касающимися программы, кажется, что, например, ssh, ffmpeg читает со стандартного ввода, фактически не используя его, поэтому первый вызов Convert потребляет оставшуюся часть списка файлов после того, как read получает первую строку. Попробуйте это

Convert() {
    ffmpeg -i "$1" -vcodec mpe4 -sameq -acodec aac \
           -strict experimental "$1.mp4" < /dev/null
}

Таким образом, ffmpeg не будет "захватывать" данные со стандартного ввода, предназначенного для команды read.

Ответ 2

[...]

for i in `cat list.txt`

Никогда не используйте этот синтаксис:

for i in $(command); do ...; done # or
for i in `command`; do ...; done

Этот синтаксис читает вывод командного слова по слову, а не строку за строкой, что часто создает неожиданные проблемы (например, когда строка содержит некоторые пробелы и когда вы хотите читать строку, например, например, элемент).

Всегда есть более разумное решение:

command|while read -r; do ...; done # better general case to read command output in a loop
while read -r; do ...; done <<< "$(command)" # alternative to the previous solution
while read -r; do ...; done < <(command) # another alternative to the previous solution
for i in $DIR/*; do ...; done # instead of "for i in $(ls $DIR); do ...; done
for i in {1..10}; do ...; done # instead of "for i in $(seq 1 10); do ...; done
for (( i=1 ; i<=10 ; i++ )); do ...; done # such that the previous command
while read -r; do ...; done < file # instead of "cat file|while read -r; do ...; done"
# ...

Я написал курс с более подробной информацией об этом предмете и повторяющимися ошибками, но по-французски, к сожалению:)

Чтобы ответить на исходный вопрос, вы можете использовать что-то вроде:

Convert() {
    ffmpeg -i "$1" -vcodec mpe4 -sameq -acodec aac -strict experimental "$1.mp4"
}

Convert_loop(){
   while read -r; do
       Convert $REPLY
   done < $1
}

Convert_loop list.txt

Ответ 3

KISS! =)

convert() {
    ffmpeg -i "$1" \
           -vcodec mpe4 \
           -sameq -acodec aac \
           -strict experimental "${1%.*}.mp4"
}

while read line; do
    convert "$line"
done < list.txt