奇怪的文件名排序(bash、ls、sort)

奇怪的文件名排序(bash、ls、sort)

今天是个好日子。

我正在尝试将我的音乐提供给 mplayer,就像这样:mplayer *,但是曲目顺序错误。

以下是我用ls(以及ls -1ls -1 | sort)得到的结果,请注意音乐会中数字“I”、“II”、“III”的顺序:

Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: II.Largo e Spiccato.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: I. Adagio e spiccato.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: II.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: III.Larghetto.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: IV. Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: II.Largo.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: I.Adagio.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: II.Allegro assai.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: II.Largo.mp3

看起来,排序是通过曲目名称而不是曲目编号来执行的,我该如何告诉 bash 按字典顺序对文件进行排序?

以下是一些可能相关的信息:

$ LC_ALL=C type ls
ls is aliased to `ls --color=auto'
$ locale
LANG=ru_RU.UTF-8
LANGUAGE=
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=
$ LC_ALL=C bash --version
GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
$ LC_ALL=C ls --version
ls (GNU coreutils) 8.13
Copyright (C) 2011 Free Software Foundation, Inc.

更新。我将两个文件名存储到文件中:

$ ls -1 | head -n1 > fname1; ls -1 | head -n2 | tail -n1 > fname2

meld然后用( GUI)检查这两个文件,diff以确保其中没有不可拆分空格之类的字符,因为这些字符可能会扰乱排序。所以……没有这样的字符,除了明显可见的字符外,没有任何区别。第二个和第三个文件名也是如此。

答案1

您可以在命令执行期间临时设置您的语言环境:我将您的文件列表放在名为的文件中files

你看到什么了:

$ LC_ALL='ru_RU.UTF-8' sort files
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: II.Largo e Spiccato.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: I. Adagio e spiccato.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: II.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: III.Larghetto.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: IV. Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: II.Largo.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: I.Adagio.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: II.Allegro assai.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: II.Largo.mp3

按您想要的排序:

$ LC_ALL=C sort files
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: II.Largo e Spiccato.mp3
Antonio Vivaldi - Op.3 concerto No.1 D-dur RV 549: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: I. Adagio e spiccato.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: II.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: III.Larghetto.mp3
Antonio Vivaldi - Op.3 concerto No.2 g-moll RV 578: IV. Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: II.Largo.mp3
Antonio Vivaldi - Op.3 concerto No.3 G-dur RV 310: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: I.Adagio.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: II.Allegro assai.mp3
Antonio Vivaldi - Op.3 concerto No.4 e-moll RV 550: III.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: I.Allegro.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: II.Largo.mp3
Antonio Vivaldi - Op.3 concerto No.5 A-dur RV 519: III.Allegro.mp3

具体来说,您需要将LC_COLLATE变量设置为C

答案2

由于您已经解决了您的问题(至少对于最多 8 个罗马数字),因此这是一个一般性的评论:

ls *在将文件传递到音乐播放器时检查文件顺序并不是一个好选择mplayer *。这是因为ls它本身可以重新排列文件——并且它绝不保证该机制与 shell 使用的机制相同。这取决于您的设置。改用echo *-- 或 以获得更漂亮的输出printf "%s\n" *

此示例通过我的个人别名说明了这一点ls="ls -v"

$ touch 1 2 3 12
$ ls *
1  2  3  12
$ echo *
1 12 2 3
$ printf "%s\n" *
1
12
2
3

使用 可以实现更好的解决方案zsh,但据我所知 不能使用bash

Mikael Magnusson 发布了宏伟的功能处理 zsh 邮件列表中的罗马数字。不深入讨论函数本身的细节,它的工作方式如下:

$ touch I II III IV V VI VII VIII IX X L C D M
$ print *
C D I II III IV IX L M V VI VII VIII X
$ print *(no+romansort)
I II III IV V VI VII VIII IX X L C D M

最后,打印命令(no+romansort)告诉 shell,你想要对数字进行排序 ( n) 并使用自定义函数 ( o+) 首先解析文件名。

当罗马数字只是文件名的一部分时,这当然有效。但请注意,您需要HIST_SUBST_PATTERN设置该选项!

答案3

由于某种原因,在 Mac OSX (10.8.3) 上排序确实按正确的顺序对罗马数字进行排序。

尽管如此,在进行排序之前,先用罗马数字代替怎么样?

cat filename.txt | sed 's/IV/4/g' | sed s'/III/3/g' | sed 's/II/2/g' | sed 's/I/1/g' | sort

这对我来说是有效的(但我再次在 OSX 上尝试了这个)。

相关内容