Convert FLAC files to MP3 in parallel on Ubuntu I created a script to convert my FLAC music collection to MP3.  I did this so that I can play the MP3 files in my car, as the integrated head unit only supports MP3 and WMA files.  The script works on my Ubuntu system.  Are there any opportunities to improve its efficiency?

I chose to use ffmpeg to transcode and GNU parallel to utilize all CPU cores/threads.

Iteration 1

 #!/bin/bash

 ## Converts flac to mp3

 if ! dpkg-query -W -f='${Status}' ffmpeg | grep "ok installed"; then
 apt-get update  &amp;&amp; apt-get install ffmpeg; fi

 if ! dpkg-query -W -f='${Status}' parallel | grep "ok installed"; then
 apt-get update  &amp;&amp; apt-get install parallel; fi

 parallel -i -j$(nproc) \
         ffmpeg -n -i {} -acodec libmp3lame -ab 320k -map_metadata 0 -id3v2_version 3 {.}.mp3 ::: */*/*/*.flac


Iteration 2

 #!/bin/sh

 ## Converts flac to mp3

 die() { echo "$@" &gt;&amp;2; exit 1; }

 ### Check the preconditions

 if ! dpkg-query -W -f='${Status}' ffmpeg | grep "ok installed"; then
     apt-get update  &amp;&amp; apt-get install ffmpeg libmp3lame parallel;
 fi

 ####

 flac_to_mp3() {
     ffmpeg -n -i "$1" -acodec libmp3lame -ab 320k \
        -map_metadata 0 -id3v2_version 3 "$2"
 }
 export -f flac_to_mp3

 parallel flac_to_mp3 {} '{.}.mp3' ::: */*/*/*.flac
shellcheck

It is always a good plan to run your code through shellcheck.net.  This only reveals a couple of issues:


Your -j$(nproc) should be quoted to avoid word splitting.  Hopefully no one will put spaces in nproc, but just in case -j"$(nproc)" would handle it better.  As noted in a comment above you may be able to drop this totally
Your {.}.mp3 bothers shellcheck which is also correctable with quoting like '{.}.mp3'.


ifs

I really like that you're using the direct exit value checking with your ifs.  This is a great shell feature that is not terribly popular.

I wish you would indent them a bit better though:

if ! dpkg-query -W -f='${Status}' ffmpeg | grep "ok installed"; then
    apt-get update  &amp;&amp; apt-get install ffmpeg;
fi


Lining up the if and the fi makes me feel better.  Having the conditional things indented also helps following along much easier.

shorter line length is good

You're already using \ to split up the long parallel line, so why not split the ffmpeg part of it in two so it all fits in 80 columns?

efficiency

Using parallel to manage the process seems like a good plan.  This operation should be CPU bound so it will do a good job for getting this done.  You might want to have some CPU and I/O monitoring going to make sure this is working as expected.

Your script does not seem to consider that some mp3s might already be there.  If your computer crashed in the middle of conversion you would be stuck redoing work already completed.

apt minimization

While it is a tiny part of what you're doing the apt portion of things could be more efficient.  You could cache whether these commands are installed by touching a file like ~/.ready_to_convert and hoping they don't get uninstalled by accident.  You could also choose to skip the dpkg-query and just see if which ffmpeg gives you any output.  This would let it work even if the commands are installed manually in /usr/local/bin without a package.

It would also be nice to only run apt-get update once.  You could set a flag like so:

if ! dpkg-query -W -f='${Status}' ffmpeg | grep "ok installed"; then
    apt-get update  &amp;&amp; apt-get install ffmpeg
    APT_UPDATED=1
fi

if ! dpkg-query -W -f='${Status}' parallel | grep "ok installed"; then
    if [[ $APT_UPDATED &lt; 1 ]]; then
        apt-get update
    fi
    apt-get install parallel
fi


But presumably the conversion is consuming most of the time so this will only let that get started a second or two quicker.