Преобразование нескольких рекурсивных видеофайлов с помощью find и avconv

Для преобразования файлов MOV в mp4 в каталоге я использовал (я использую больше команд с avconv, но я сократил для syntetize):

for f in *.MOV; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done

И это работает. Он конвертирует каждый файл.

Но теперь я хочу преобразовать все файлы в каталоге и во всех подкаталогах (рекурсивно). Я попытался:

for f in "$(find ./ -name '*.MOV')"; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done

Но это не работает, потому что выводит:

mario@circo3d:~/Imágenes$ for f in "$(find ./ -name '*.MOV')"; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done
Converting ./2015-05-23 Tutorial Masa de colores/MVI_9219.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9196.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9199.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9200.MOV
avconv version 9.18-6:9.18-0ubuntu0.14.04.1, Copyright (c) 2000-2014 the Libav developers  built on Mar 16 2015 13:19:10 with gcc 4.8 (Ubuntu 4.8.2-19ubuntu1)
./2015-05-23 Tutorial Masa de colores/MVI_9219.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9196.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9199.MOV
mario@circo3d:~/Imágenes$ 

(последний список файлов отображается красным цветом)

Кажется, что find работает, он входит в каждую директорию и также echo "Converting $f"... но avconv получает все эти имена файлов в виде списка с символами новой строки, а не каждый один элемент из цикла for.

Почему echo работает, а avconv нет?

Or...

Почему for f in *.MOV' работает с avconv, а for f in "$(find ./ -name '*.MOV') не работает?


person Mario Mey    schedule 29.07.2015    source источник
comment
Что вы получите, если скажете for f in "$(find ./ -name '*.MOV')"; do echo "$f"; done? То есть он находит все файлы — и только все — которые вы хотите обработать?   -  person fedorqui 'SO stop harming'    schedule 29.07.2015
comment
Я получаю список файлов .MOV, которые находятся в каталоге и подкаталогах. Все и только файлы, которые я хочу обработать. Нравится: ./2015-05-23 Учебник Маска де Colores/MVI_9219.MOV ./2015-05-23 Учебник Маска де Colores/MVI_9196.MOV ...   -  person Mario Mey    schedule 30.07.2015


Ответы (2)


Это потому, что вы поставили их в кавычки. В POSIX в имени файла вполне может присутствовать символ новой строки.

Самым простым решением для вас было бы переписать, используя атрибут -exec find:

find . -name "*.MTS" -exec echo {}  \; -exec avconv -i {} {}.mp4 \;

Или, что еще лучше, вы можете использовать -execdir для строки avconv, она выполнит команду из каталога, в котором находится файл.


Из вашего комментария я вижу, что вам трудно понять, откуда вообще берутся новые строки. Так

На справочной странице поиска:

If no expression is given, the  expression  -print  is  used

и

-print True; print the full file name on the standard output,  followed
       by  a  newline.

Так что find на самом деле печатает для вас все символы новой строки. Вы вызываете его через $(find ...), а затем заключаете в кавычки, что означает, что все символы новой строки сохраняются как обычные символы.

Вот почему ваш цикл for выполняется только один раз.

Если вам абсолютно необходимо использовать цикл, а не использовать собственное выполнение find, вы, вероятно, захотите использовать цикл while:

find . -name "*.MTS" | while read f; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done
person v010dya    schedule 30.07.2015
comment
Три вещи: 1.- Это другая техника. Я хотел бы знать, почему мой не работает. 2.- Почему вы говорите о символе новой строки... в то время как в моих файлах нет новых строк? (в них есть только пробелы) 3.- Как с помощью этой техники получить имя файла без расширения? Например, ${f:0: -4}.mp4. - person Mario Mey; 30.07.2015
comment
@MarioMey Я отредактировал ответ, предоставив некоторую информацию о том, откуда взялась новая строка. Я также предоставил вам способ сделать это в другом цикле (цикле while) - person v010dya; 30.07.2015
comment
Теперь я понимаю, где была новая строка. Но мне так сложно понять эти... такие вещи с именами файлов... Я лучше вернусь к своей работе. Цикл while работает отлично, только перед выполнением не хватает точки с запятой. С этого момента я буду использовать это предложение. Я добавил некоторые параметры кодека и gvfs-trash для удаления файла. Спасибо чувак. - person Mario Mey; 30.07.2015

Я использую sox для преобразования mp3 в файлы alaw. Очень похожий случай. Использование простого bash-скрипта.

#!/bin/bash

for file in $(find . -name '*.mp3')
do
    echo $file
    sox $file -t al -c 1 -r 8000 $(echo "$file" | sed -r 's|.mp3|.alaw|g')
done
person Oleksii Radetskyi    schedule 25.09.2019