Mario Mey
Mario Mey

Reputation: 1702

Convert multiple recursive video files using "find" and "avconv"

For converting MOV files to mp4 in the directory, I was using (I use more commands with avconv, but I shortened for syntetize):

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

And it works. It converts every file.

But now, I want to convert all the files in the directory and all subdirs (recursivelly). I tried:

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

But it doesn't work, because it outputs:

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$ 

(Last file list appear in red)

It seems that find works, it enters in every dir and echo "Converting $f" too... but avconv receives all that filenames as a list with newlines, not each one element from the "for" loop.

Why echo works and avconv doesn't?

Or...

Why for f in *.MOV' works with avconv and for f in "$(find ./ -name '*.MOV') doesn't?

Upvotes: 1

Views: 995

Answers (2)

Oleksii Radetskyi
Oleksii Radetskyi

Reputation: 227

I use sox to convert mp3 to alaw files. Very similar case. Using simple bash script.

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

Upvotes: 0

v010dya
v010dya

Reputation: 5848

This is because you put them in quotes. In POSIX a newline character can very well be present in the name of the file.

The easiest solution for you would be to rewrite using -exec attribute of find:

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

Or even better, you could use -execdir for the avconv line, it will execute the command from the directory where the file is found.


From your comment i see that you are having difficulty seeing where the newlines are coming from at all. So

From man page of find:

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

and

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

So find actually prints all the newline characters for you. You are calling it via $(find ...) and then you place it in quotes, which means that all the newline characters are preserved as a regular character.

This is why your for loop executes only once.

If you absolutely must use a loop, rather than using find's own execution, you probably want to use a while loop:

find . -name "*.MTS" | while read f; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done

Upvotes: 1

Related Questions