Bash - calculate length of all mp3 files in one folder

Viewed 4064

I have the following command which returns the filenames and lengths of mp3s files:

mp3info -p "%f: %m:%02s\n" *.mp3

How can I use this in a bash script to return the total length (sum) of all mp3 files in a given directory? I would like to have the following notation: mm:ss

5 Answers

This Bourne shell one-liner, when used inside a directory containing only music files, will output their total length in seconds with a very high degree of precision:

LENGTH=0; for file in *; do LENGTH="$LENGTH+$(ffprobe -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)"; done; echo "$LENGTH" | bc

Modified to only output the length of .mp3 files (and thus avoid breaking on the innocuous .docx sitting within our music directory), it would look like this:

LENGTH=0; for file in *.mp3; do if [ -f "$file" ]; then LENGTH="$LENGTH+$(ffprobe -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)"; fi; done; echo "$LENGTH" | bc

And if, for example, we wanted to output the total length of audio with only several different file extensions, we can do that as well by adding a second wildcard, still avoiding the dreadful, scary .docx:

LENGTH=0; for file in *.mp3 *.ogg; do if [ -f "$file" ]; then LENGTH="$LENGTH+$(ffprobe -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)"; fi; done; echo "$LENGTH" | bc

Naturally, ffmpeg has to be installed to use either of these.

Here's a variation of @albfan's kind answer with descriptive variable names and syntax highlighting. It works for an entire directory of directories (albums).

#!/bin/bash

TOTAL=0

for ALBUM in *
do
    if [ -d "${ALBUM}" ] ; then
        ALBUM_TIME=0
        echo ${ALBUM}

        # Make `cd` quiet
        cd "${ALBUM}" &>/dev/null
        for TRACK in *.mp3; do
            TRACK_TIME="$(soxi -D "${TRACK}" 2>/dev/null)"
            # noisy
            # echo "Track duration: $TRACK_TIME"
            [[ "$TRACK_TIME" != "" ]] && ALBUM_TIME="$ALBUM_TIME + $TRACK_TIME"
        done
        # Convert summation to a single number for efficiency
        ALBUM_TIME=`echo $ALBUM_TIME | bc`
        # This has to be two stmts?
        echo -n "Album time (min): "; echo 'scale=2;' ${ALBUM_TIME} / 60 | bc
        echo # line break
        TOTAL="$TOTAL + $ALBUM_TIME"
        cd ..
    fi

    # Evaluate the expression
    TOTAL=`echo $TOTAL | bc`

done

echo -n "Total time (hrs): "; echo 'scale=2;' ${TOTAL} / 3600 | bc

A one-liner to rule them all:

mp3info -p '%S\n' *.mp3 | awk '{s+=$1} END {printf"%d:%02d:%02d\n",s/3600,s%3600/60,s%3600%60}'
Related