用人類可讀格式的數字進行擴展

用人類可讀格式的數字進行擴展

因此,我想在以檔案名稱作為輸入的控制台播放器中播放一些 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

相關內容