Então, quero reproduzir alguns MP3s em um reprodutor de console que receba nomes de arquivos como entradas. Eu tenho os seguintes arquivos, conforme indicado por ls -1 *
onde *
são expandidos pelo meu shell (zsh):
1 - Main title.mp3
10 - End title.mp3
2 - Intro.mp3
...
Mas claramente, como eu realmente quero que eles sejam ordenados é assim:
1 - Main title.mp3
2 - Intro.mp3
...
10 - End title.mp3
Que mágica de expansão de shell eu preciso para fazer isso?
Eu sei que poderia conseguir a mesma coisa com alguns canos inteligentes, sort -h
mas isso não é realmente uma opçãoporque sou um digitador preguiçoso. Então, a menos que eu tenha escrito um pequeno script de shell para adicionar música, prefiro fazer nyxmms2 add /path/to/dir/*.mp3
isso porque estou procurando como fazer a filtragem na expansão do zsh ... Além disso, quero saber se isso é possível porque se aplica a muitas outras situações também - por exemplo, arquivos de log ou revisões ou ...
Responder1
Use on
qualificador global.
print -lr -- *.mp3(n)
Você pode alterar a ordem de classificação padrão definindo onumeric_glob_sort
opção.
setopt numeric_glob_sort
print -lr -- *.mp3
Se você precisar de uma ordem lexicográfica para um padrão enquanto numeric_glob_sort
estiver em vigor, negue o n
qualificador glob.
print -lr -- *(^n)
Responder2
Uma abordagem seria executar a saída ls
por meio do comando sort
para controlar como a saída é exibida.
Você pode usar o -h
(também conhecido como --human-numeric-sort
) que classifica as coisas em formato legível por humanos.
$ ls | sort -h
1 - Main title.mp3
2 - Main title.mp3
10 - Main title.mp3
EDIT # 1 - abordando o comentário do OP
O texto acima pode ser agrupado em um alias como este:
$ alias lss="ls | sort -h"
A execução do comando acima seria reduzida a isto:
$ lss
1 - Main title.mp3
2 - Main title.mp3
10 - Main title.mp3
Referências
Responder3
Você pode alterar a ordem de classificação no zsh
globbing (vejaResposta de Gilles), mas ls
classificará seus argumentos de qualquer maneira e, por padrão, lexicograficamente.
Se o seu ls
for o GNU ls
, você pode usar a -v
opção de ordenar numericamente:
ls -1v
Ou:
ls -1vd -- *
Não é equivalente a sort -h
porque sort -h
é classificar coisas como a saída de du -h
, que é onde 1.12G
é maior que 999M
, enquanto os qualificadores globais de and ls -v
são voltados para classificar coisas como números de versão (onde 1,20 é maior que 1,4, por exemplo).zsh
(n)
Se você quiser um globbing que entenda isso é suficiente, você precisará escrever uma função zsh sort para isso.
Com o zsh, você pode definir a ordem de classificação glob com uma função e usá-la como arquivo *(o+that-function)
. that-function
pega o nome do arquivo para classificar na $REPLY
variável e deve retornar para a mesma variável, algo que zsh
pode então ser classificado lexicograficamente (ou numericamente, se n
também for fornecido).
Algo como:
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))}
}
substituiria todos os 1.1G pelo seu valor (1181116006,4).
Que você pode usar como:
ls -1Ud -- *(no+h)
( -U
sendo a ls
opção GNU para contarls
nãopara classificar seus argumentos).
No entanto, isso não funcionará bem com números com uma parte fracionária, como seria, 1.20
por 1.3
exemplo:
$ ls
1.20 1.3 3.1G 500M
$ ls -v1Ud -- *(no+h)
1.3
1.20
500M
3.1G
Para algo que classificaria todos os tipos de números decimais flutuantes com opções suficientes (como -1e20M, 1E-20, 100k, 3000M), porque zsh
só pode classificar lexicograficamente ou numericamente limitado a números inteiros decimais positivos, precisaríamos de uma função para convertê-los em strings que classificam lexicograficamente na mesma ordem ou inteiros decimais positivos que classificam numericamente na mesma ordem.
zsh
faz aritmética de ponto flutuante e decimal com números de 64 bits quando disponíveis, então poderíamos aplicar uma função de ponto flutuante que transforma esses números (ou pelo menos o intervalo suportado por zsh
números flutuantes) em um número inteiro de 0 a 2 63 . Usar a função logaritmo pode ser uma opção. Algo como:
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)))))]}
}
Para ser usado como:
print -rl -- *(no+h)
Ou, voltando à classificação numérica para diferenciar 100000000000000001 e 10000000000000002, por exemplo (que têm o mesmo logaritmo com zsh
precisão flutuante):
print -rl -- *(noe:h:on)
Então, obtemos algo ainda melhor do que 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
Agora, para o seu problema específico do nyxmms2, para complementar a resposta de Gilles, se você é um digitador preguiçoso, também pode definir desta vez umseleção(em vez de "ordenar") função para arquivos de música, como:
m() [[ $REPLY == (#i)*.(mp3|ogg)(-.) ]]
nyxmms2 *Zep*(n+m)
Ou use uma variável:
m='.(#i)(mp3|ogg)(n-.)'
nyxmms2 *Zep*$~m
Ou um alias global:
alias -g @m='./*.(#i)(mp3|ogg)(n-.)'
nyxmms2 @m
Para ativar nyxmms2
apenas o numericglobsort, você poderia fazer:
preexec() {[[ $1 = nyxmms2* ]] && setopt numericglobsort}
precmd setopt nonumericglobsort
Responder4
você sempre pode usar a expansão do shell para fazer isso.
nyxmms2 add $(ls /path/to/dir/*.mp3 | sort -n)
já que você está lidando com música, você pode criar "listas de reprodução"
ls /path/to/album/or/song/*.mp3 | sort -n >> /path/to/playlist
nyxmms2 add < /path/to/playlist