Bluesky

Email

Tumblr

Webtip:

Hover over a link or an image to show a tooltip!

prefix_files_by_track.sh

Author: Packrat

Version: 0.1

Summary

For every file in the directory inside which this script gets executed:
A query is made using ffmpeg to find a track number in that file's meta data.
If one is found, that file's name will be prefixed with the track number, preceded with a number of zeros based on the determined maximum number of zeros.

Why?

Some audio players ignore the track number metadata when listing audio files in a directory, and instead order by filename. I don't know why this is done. This over-elaborate script helps with that issue.


Dependencies


P.S.: in case you don't know, editing tags is pretty simple:
$ ffmpeg -i file.mp3 -metadata TRACK={TRACK NUMBER HERE} -codec copy output.mp3
This can edit any metadata you'd like, such as TRACKTOTAL.

Note: -codec copy simply copies encoding to the new file. Without this option, ffmpeg will re-encode, which takes time and reduces sound quality.

Code Preview

#!/bin/bash
# iterates files in current directory
# if the file has track metadata found using ffprobe:
# its name will be configured to reflect its corresponding track number

# TODO protect files from being overwritten
# when implementing mv, be sure to include -n

# TODO create failsafe in the case of multiple tracks sharing the same track number

let MAX_TRACK=0
let GREATEST_TEN=1000 # i seriously doubt an album will exceed this number of tracks
# bump up this number if somehow that's the case
echo ""
echo "Prefix Files By Track v0.1"
echo "--------------------------------"
echo "AUTHOR: Packrat"
echo "COMPANY: GMR Toolz & Software"
echo "UNLICENSED"
echo ""
echo '+----------------------------------+
| ### # # #### |
| # # ## ## # # |
| # # ## # #### |
| # ## # # # # |
| # # # # # # |
| #### # # # # |
+----------------------------------+'
echo ""
echo "IN USING THIS SCRIPT, YOU ARE WAIVING PACKRAT OF ALL LIABILITY FOR ANY DAMAGES CAUSED BY HIS SUBPAR PROGRAMMING"
echo "YOU'VE BEEN WARNED"
echo ""

echo 'Continue?'
read -p 'y/n : '


declare -A TRACKS
declare -A ORIGINAL_NAMES
ALBUM=""
ARTIST=""

sample_file() {
echo ?
if [ $# -gt 0 ]; then
TRACK="$(ffmpeg -i "$1" 2>&1>/dev/null | grep -iwe 'TRACK' -iwe 'ALBUM' -iwe 'ARTIST')"
ALBUM=$(echo "$TRACK" | grep -iw "ALBUM" | sed -E 's/^[^:]*://')
ARTIST=$(echo "$TRACK" | grep -iw "ARTIST" | sed -E 's/^[^:]*://')

fi
}

collect_track_metadata() {
for FILE in *; do
TRACK="$(ffmpeg -i "$FILE" 2>&1>/dev/null | grep -iwe 'TRACK' -iwe 'ALBUM' -iwe 'ARTIST')"
echo $TRACK?
A=$(echo "$TRACK" | grep -iw "ARTIST" | sed -E 's/^[^:]*://')
if [ "$A" != "$ARTIST" ]; then
echo "Artist isn't a match, giving up"
echo "$A!"
echo "$Artist!"
continue
fi
A=$(echo "$TRACK" | grep -iw "ALBUM" | sed -E 's/^[^:]*://')
if [ "$A" != "$ALBUM" ]; then
echo "Album isn't a match, giving up"
echo "$A!"
echo "$Album!"
continue
fi
# check that grep found an instance of "track". returns non-zero exit if it did not
if [ $? -gt 0 ]; then
continue
fi
# remove whitespace, ensure its interpreted as a base10 integer
let TRACK=10#$(echo "$TRACK" | grep -iw "track" | sed -E 's/^[^:]*://' | sed -E 's/\ //g')
if [ $TRACK -gt $MAX_TRACK ]; then
let MAX_TRACK=$TRACK
fi
ORIGINAL_NAMES[$TRACK]="$FILE"
FILE=$(echo $FILE | sed -E 's/\ /_/g')
TRACKS["$FILE"]=$TRACK
done
}

prefix_filenames_with_max_track_number() {
for file in ${!TRACKS[@]}; do
while true; do
let A=$MAX_TRACK/$GREATEST_TEN
if [ $A -ge 1 ]; then
break
fi
let GREATEST_TEN=$GREATEST_TEN/10
if [ $GREATEST_TEN -le 1 ]; then
break
fi
done

done
# hold the new tracks in a new array ordered from lowest to highest
declare -a NEW_TRACKS
# rename the files
for FILE in ${!TRACKS[@]}; do
TRACK=${TRACKS["$FILE"]}
INDEX=$TRACK
I=0
while true; do
let B=10**$I
let A=$TRACK*$B
let A=$A/$GREATEST_TEN
if [ $A -lt 1 ]; then
let I=$I+1
continue
fi
break
done
for ((x=0; x < $I; x++)); do
TRACK="0$TRACK"
done
NEW_TRACKS[$INDEX]="$TRACK.${ORIGINAL_NAMES[$INDEX]}"
done
echo ""
for NEW_TRACK_NAME in "${NEW_TRACKS[@]}"; do
echo "$NEW_TRACK_NAME"
done

echo "Commit?"
read -p "y/n : "
if [ $REPLY == "y" ]; then
echo "DOIN IT"
fi
for INDEX in ${!NEW_TRACKS[@]}; do
cp "${ORIGINAL_NAMES[$INDEX]}" "${NEW_TRACKS[$INDEX]}"
done

}

sample_file $1
collect_track_metadata
prefix_filenames_with_max_track_number

echo ${!ORIGINAL_NAMES[@]}
for i in ${!ORIGINAL_NAMES[@]}; do
echo $i
echo "${ORIGINAL_NAMES[$i]}"
done


©gunmetalrats 2026-2026
Last update:
00:00:00 01-01-1970