0

I have a bash script that converts *.mkv files to *.avi files. Here's what it looks like:

#!/bin/bash
for f in $(ls *mkv | sed ‘s/\(.*\)\..*/\1/’)
do
ffmpeg -i $f.mkv -sameq $f.avi
done

What I need this script to do however, is it needs to search recurssively in all folders for *.mkv files and then run the ffmpeg command and save the output to the same directory.

PLEASE can someone help me? :-)

justinhartman
  • 682
  • 7
  • 20

5 Answers5

4
find /some/path -name '*.mkv' | while read f
do
    ffmpeg -i "$f" -sameq "${f:0:-4}.avi"
done
lanzz
  • 42,060
  • 10
  • 89
  • 98
  • Ugh. Never use sed to just replace an extension in a variable. – Jens May 26 '12 at 20:26
  • Ugh2. Never use a bashism when a POSIX solution does it :-) `${f%mkv}avi`. Thanks for listening; a rare trait these days... +1 – Jens May 26 '12 at 20:58
  • pattern matching is a waste of cpu cycles where you already know that you need to strip a fixed number of chars, even if it is a bashism. – lanzz May 26 '12 at 21:01
  • @lanzz I keep getting this output: – justinhartman May 27 '12 at 15:37
  • `Justins-MacBook:Desktop justinhartman$ sh mkv2avi.sh` `mkv2avi.sh: line 4: -4: substring expression < 0` – justinhartman May 27 '12 at 15:38
  • Sorry, turns out to work only with more recent versions of `bash`. Change `${f:0:-4}.avi` to `${f%.mkv}.avi`. @Jens, it finally boils down to a POSIX solution :) – lanzz May 27 '12 at 15:43
2

Try like this:

find <file_path> -name '*.mkv' -exec sh -c 'mv "$0" "${0%%.mkv}.avi"' {} \;
Rahul
  • 76,197
  • 13
  • 71
  • 125
  • You seem to be missing a semicolon at the end. – Dennis Williamson May 26 '12 at 20:26
  • 2
    You also seem to think that conversion from Matroska to AVI is a simple matter of a rename. – lanzz May 26 '12 at 20:28
  • I would use two percent signs in the parameter expansion to make sure that you only remove the ".mkv" at the end. This protects against the rare case when ".mkv" might appear more than once in the name. – Dennis Williamson May 26 '12 at 20:29
  • @Dennis, Not sure but went with the assumption that file name will be like somemkvfile.mkv. – Rahul May 26 '12 at 20:31
  • @lanzz, frankly; no idea about `ffmpeg` command or `Matroska` (Heard that first time) but this is the simplest way ... renaming with `mv` command, that's what generally I do. So, suggested that. – Rahul May 26 '12 at 20:33
  • It is the simplest way to rename a file. What @justinhartman is trying to do is to mass-convert video from one format to another. – lanzz May 26 '12 at 20:35
  • 1
    @Rahul @lanzz this seems to work nicely using ffmpeg: `find /Users/justinhartman/Movies/Game\ of\ Thrones -name '*.mkv' -exec sh -c 'ffmpeg -i "$0" -sameq "${0%%.mkv}.avi"' {} \;` – justinhartman May 27 '12 at 15:43
  • @Rahul you're a star, thanks a million and thanks very much to everyone who commented on this post! – justinhartman May 27 '12 at 15:50
1
#!/bin/bash
find . -name "*.mkv" -exec ffmpeg -i {} -sameq `basename {} .mkv`.avi \;
kjp
  • 3,086
  • 22
  • 30
1

Thanks to @Raul this is what worked for me and is the solution to what I wanted to do which is run recursively through directories and run the ffmpeg command on mkv files:

#!/bin/bash
find <file_path> -name '*.mkv' -exec sh -c 'ffmpeg -i "$0" -sameq "${0%%.mkv}.avi"' {} \;
exit;
justinhartman
  • 682
  • 7
  • 20
0

Instead of ls *.mkv use find . -name "*.mkv".

This assumes no funny filenames (no spaces, newlines). Another possibility is using find in conjunction with xargs. The xargs manual makes for an instructive reading which will save your scripting life one day :-)

Jens
  • 69,818
  • 15
  • 125
  • 179
  • instead of `find ...` use `for f in *.mkv` -- then you don't have to care about funny filenames as long as you quote the variable. – glenn jackman May 26 '12 at 23:22
  • But this does not do directory recursion, which is exactly the problem at hand. – Jens May 27 '12 at 07:24