Search code examples
bashfilerandommp3

How to randomly select a song I haven't heard in a while and play it


Shuffling mp3 files often results in hearing a track that recently played. So I decided to use the 'touch' command to update the 'last modified' date & time of a file. I want my script to randomly select a song from the 10 songs that I haven't heard in the longest amount of time.

I came up with this:

ls -t $music_folder | tail -n 10 | sort -R | tail -n 1 | while read file; do
 echo $music_folder$file
 mplayer $music_folder$file
done

I have not yet added the 'touch' line to update the song that's about to play.

This lists the files in $music_folder sorted by time last modified, looks only at the 10 that haven't been touched in the longest time, randomizes the sort order of those ten, then grabs the one at the bottom of the list.

The 'echo' line works perfectly. However, when I try to play the song with mplayer, it tries to play several files where each word of the results is a different file name. Why is it not passing $file as a single string of text? And how can I get mplayer to play the file shown in the echo line?


Solution

  • Solution

    Put double quotes around the shell variables. For example:

    mplayer "$music_folder$file"
    

    Discussion

    The problem is that bash, like all other POSIX shells, performs pathname expansion and word splitting on unquoted shell variables. To illustrate, let's work in a directory with three files:

    $ ls
    1.mp3  2.mp3  3.mp3
    

    Now, let's define a variable and expand it without quoting:

    $ var="dir/Joe's song *.mp3"
    $ printf "%s\n" $var
    dir/Joe's
    song
    1.mp3
    2.mp3
    3.mp3
    

    Observe that dir/Joe's and song were separated: this is word splitting. Further, *.mp3 became a list of files in the directory: this is pathname expansion. Both of these, however, can be suppressed with the use of double quotes:

    $ printf "%s\n" "$var"
    dir/Joe's song *.mp3
    

    This is what you wanted.

    For completeness, let's consider single-quotes:

    $ printf "%s\n" '$var'
    $var
    

    Inside single-quotes, the shell expands nothing. Consequently, as shown above, the even four characters $var remain unchanged.