Swallowing my ogg, passing mp3

I’m still an idealist. I still plan on using ogg vorbis instead of mp3. However, the convenience of just using iTunes for listening to music is too great.


Four hundred seventy-four ogg vorbis files that I don’t get to play with iTunes. All of which I have ripped myself from my own CDs. All of which I’ve been missing the sound of due to lack of iTunes ogg playback. Today I implemented my interim solution. I’ll put mp3 files right next to the oggs.

http://marginalhacks.com/bin/ogg2mp3 has a nifty perl script, which could just as easily be shell, but in a linux world, we always have perl 🙂

This script uses ogg123 to extract a wav file from the ogg, then uses lame to encode that wav file. Coupled with my shell prowess, I can put mp3s right next to all my oggs.

What shell prowess? I like this oneliner.

find . -name '*.ogg' | while read i ; do if [[ ! -e "${i%%.ogg}.mp3" ]] ; then echo doing $i ; ~/src/ogg2mp3 "$i" ; fi ; done

Not a oneliner you say? Well I typed and constructed it on one line.

Maybe this is easy to read?

find . -name '*.ogg' |
while read i
if [[ ! -e "${i%%.ogg}.mp3" ]]
echo doing $i
~/src/ogg2mp3 "$i"

I love bash.

If you aren’t a master of the shell, then you may want to know just what is going on here.

I used find and piped to while read. why?

I could have used for i in `find`, but for splits on spaces, and many of my files have spaces in the name, so I used while read to capture the entire line output of find, which in this case is the filename.

I could have used find . -exec “ogg2mp3”, but then I don’t have access to shell builtins which I used to do my if statement.

My if statement checks to see if the ogg file is already there. The %% is a TrimRight function. It trims the .ogg off the end of whatever is in the i variable. Then I add the mp3. So if the mp3 doesn’t exist, then we create it. This makes it easy to stop can continue the process as well. Files that are already there will not be converted again. Of course if lame writes incrementally as it is doing the conversion, you could break in the middle of a conversion and have only part of an mp3. Don’t do that.

About the shell builtins, I used to sysadmin unix on some old slow computers. Creation of new processes was expensive. I’ve never given up always thinking about process creation and costs. ogg2mp3 wouldn’t take multiple files to convert on the command line, or else I would have used my beloved find -print0 | xargs -0 pattern. If I had used -exec and started bash instead of it, maybe something like find . -name '*.ogg' -exec 'bash -c \'if [[ ! -e ${\{\}%%.ogg}.mp3 ]]; then ...fi\''. It would have started a bash process for every cycle of the loop. Sure it is only 400+ in this case, but I’m used to scaling to 10,000, 30,000, or 100,000 … to I don’t care how big. Not to mention I find the escaping of the quotes and the curly bracets to be less readable this way. In fact, I think I have curly bracets escaped incorrectly in that -exec block. oh well.

After a day at work in Windows world, it is nice to return to the power and simplicity of the bash shell and gnu tools.