如何随机select一首好久没听的歌并播放

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

随机播放 mp3 文件通常会导致听到最近播放的曲目。所以我决定使用 'touch' 命令来更新文件的 'last modified' 日期和时间。我希望我的脚本随机 select 从 10 首我最长时间没听过的歌曲中选出一首。

我想到了这个:

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

我还没有添加 'touch' 行来更新即将播放的歌曲。

这列出了 $music_folder 中的文件,按上次修改时间排序,只查看最长时间未被触摸的 10 个,将这 10 个的排序顺序随机化,然后抓取一个在列表底部。

'echo' 行完美运行。然而,当我尝试用 mplayer 播放这首歌时,它会尝试播放多个文件,其中每个结果的单词都是不同的文件名。为什么它不将 $file 作为单个文本字符串传递?我怎样才能让 mplayer 播放回显行中显示的文件?

解决方案

在 shell 变量周围加上双引号。例如:

mplayer "$music_folder$file"

讨论

问题在于 bash 与所有其他 POSIX shell 一样,对未加引号的 shell 变量执行路径名扩展和分词。为了说明,让我们在一个包含三个文件的目录中工作:

$ ls
1.mp3  2.mp3  3.mp3

现在,让我们定义一个变量并扩展它没有引用:

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

观察到dir/Joe'ssong是分开的:这就是分词。此外, *.mp3 成为目录中的文件列表:这是路径名扩展。然而,这两者都可以通过使用双引号来抑制:

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

这就是你想要的。

为了完整性,让我们考虑单引号:

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

在单引号内,shell 不展开任何内容。因此,如上所示,偶数四个字符$var保持不变。