因此,我想在以檔案名稱作為輸入的控制台播放器中播放一些 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
可能有效,請取消n
glob 限定詞。
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 -h
is 對 的輸出之類的東西進行排序du -h
,即1.12G
大於 的地方999M
,而ls -v
和zsh
的(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