用人类可读格式的数字进行扩展

用人类可读格式的数字进行扩展

因此,我想在以文件名作为输入的控制台播放器中播放一些 MP3。我有以下文件,如我的 shell (zsh) 扩展的ls -1 *位置所示:*

1 - Main title.mp3
10 - End title.mp3
2 - Intro.mp3 
...

但显然,我实际上希望它们的排序方式如下:

1 - Main title.mp3
2 - Intro.mp3 
...
10 - End title.mp3

我需要什么 shell 扩展魔法才能做到这一点?

我知道我可以用一些聪明的管道得到同样的东西,sort -h但这并不是一个真正的选择因为我是一个懒惰的打字员。所以,除非我写了一个小的 shell 脚本来添加歌曲,否则我宁愿nyxmms2 add /path/to/dir/*.mp3这样做,为什么我正在研究如何在 zsh 的扩展中进行过滤......另外,我想知道这是否可能,因为它适用于还有很多其他情况 - 例如,日志文件或修订版或......

答案1

使用n 全局限定符

print -lr -- *.mp3(n)

您可以通过设置更改默认排序顺序numeric_glob_sort选项。

setopt numeric_glob_sort
print -lr -- *.mp3

如果您需要一种模式的字典顺序,而该模式numeric_glob_sort可能有效,请取消nglob 限定符。

print -lr -- *(^n)

答案2

ls一种方法是通过命令运行输出sort来控制输出的显示方式。

您可以使用-h(又名。--human-numeric-sort)以人类可读的形式对事物进行排序。

$ ls | sort -h
1 - Main title.mp3
2 - Main title.mp3
10 - Main title.mp3

编辑#1 - 解决OP的评论

上面的内容可以包装成一个别名,如下所示:

$ alias lss="ls | sort -h"

运行上述命令将简化为:

$ lss
1 - Main title.mp3
2 - Main title.mp3
10 - Main title.mp3

参考

答案3

您可以更改通配符中的排序顺序zsh(请参阅吉尔斯的回答),但ls无论如何都会对其参数进行排序,并且默认情况下按字典顺序排序。

如果您ls是 GNU ls,您可以使用该-v选项按数字排序:

ls -1v

或者:

ls -1vd -- *

它不等于sort -h因为sort -his 对 的输出之类的东西进行排序du -h,即1.12G大于 的地方999M,而ls -vzsh(n)通配限定符旨在对版本号之类的东西进行排序(例如,其中 1.20 大于 1.4)。

如果您确实想要一个能够理解这些的 globbing,您需要为此编写一个 zsh 排序函数。

使用 zsh,您可以使用函数定义 glob 排序顺序并将其用作*(o+that-function).that-function接受文件名在变量中排序$REPLY,并应返回到同一个变量中,然后zsh可以按字典顺序(或如果n还提供的话按数字)排序。

就像是:

h() {
  local -A x
  local match
  setopt localoptions extendedglob
  x=(k 1 K 1 M 2 G 3 T 4 P 5 E 6)
  REPLY=${REPLY//(#b)((|[0-9]#.)[0-9]##)([${(kj::)x}])/$((match[1]*2**$x[$match[3]]0))}
}

会将所有 1.1G 替换为其值 (1181116006.4)。

然后您可以将其用作:

ls -1Ud -- *(no+h)

-U作为 GNUls选项来告诉ls 不是对其参数进行排序)。

然而,这对于带有小数部分的数字效果不佳,因为它会在例如1.20之后排序1.3

$ ls
1.20  1.3  3.1G  500M
$ ls -v1Ud -- *(no+h)
1.3
1.20
500M
3.1G

对于可以对带有可选后缀的各种十进制浮点数进行排序(例如 -1e20M、1E-20、100k、3000M)的东西,因为zsh只能按字典顺序或数字顺序对正十进制整数进行排序,所以我们需要一个函数来转换这些浮点数转换为按相同顺序按字典顺序排序的字符串,或按相同顺序按数字排序的正十进制整数。

zsh在可用的情况下使用 64 位数字进行浮点和十进制算术,因此我们可以应用浮点函数将这些数字(或至少浮点数支持的范围)转换为从 0 到 2 63zsh的整数。使用对数函数可能是一种选择。就像是:

zmodload zsh/mathfunc
h() {
  local -A x
  local match v
  setopt localoptions extendedglob
  x=(k 1 K 1 M 2 G 3 T 4 P 5 E 6 Z 7 Y 8)
  REPLY=${REPLY//(#b)([-+]|)(([0-9]#.|)[0-9]##([eE]([-+]|)[0-9]##|))\
([${(kj::)x}]|)/[$(([#10]1e15*(1500+ $match[1](745+log((v=$match[2]\
${${match[2]##*[Ee.]*}:+.}*2.**$x[$match[6]]0)==0?2.48e-324:v)))))]}
}

用作:

print -rl -- *(no+h)

或者,返回到数字排序以区分 100000000000000001 和 100000000000000002 例如(它们具有相同的对数和zsh浮点精度):

print -rl -- *(noe:h:on)

然后,我们得到比以下更好的东西sort -h

$ ls | sort -h
-4
-3
+20
a2
b1
b10
b2
1e-20Y
1e3
1.20
1.3
3
20
999
1000 1e9
1000 900M
1001
1024
1k
12k
0.000000001G

$ print -rl -- *(noe:h:on)
-4
-3
0.000000001G
1.20
1.3
3
20
+20
999
1e3
1000 900M
1000 1e9
1001
1k
1024
1e-20Y
12k
a2
b1
b2
b10

现在,对于您的特定 nyxmms2 问题,为了补充吉尔斯的答案,我您是一个懒惰的打字员,您也可以定义这次选择(而不是“排序”)音乐文件的功能,例如:

m() [[ $REPLY == (#i)*.(mp3|ogg)(-.) ]]

nyxmms2 *Zep*(n+m)

或者使用变量:

m='.(#i)(mp3|ogg)(n-.)'
nyxmms2 *Zep*$~m

或者全局别名:

alias -g @m='./*.(#i)(mp3|ogg)(n-.)'
nyxmms2 @m

要仅打开 numericglobsort nyxmms2,您可以执行以下操作:

preexec() {[[ $1 = nyxmms2* ]] && setopt numericglobsort}
precmd setopt nonumericglobsort

答案4

你总是可以使用 shell 扩展来做到这一点。

nyxmms2 add $(ls /path/to/dir/*.mp3 | sort -n)

由于您正在处理音乐,您可能会创建“播放列表”

ls /path/to/album/or/song/*.mp3 | sort -n >> /path/to/playlist
nyxmms2 add < /path/to/playlist

相关内容