Expansão com números em formato legível por humanos

Expansão com números em formato legível por humanos

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 -hmas 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/*.mp3isso 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_sortopção.

setopt numeric_glob_sort
print -lr -- *.mp3

Se você precisar de uma ordem lexicográfica para um padrão enquanto numeric_glob_sortestiver em vigor, negue o nqualificador glob.

print -lr -- *(^n)

Responder2

Uma abordagem seria executar a saída lspor meio do comando sortpara 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 zshglobbing (vejaResposta de Gilles), mas lsclassificará seus argumentos de qualquer maneira e, por padrão, lexicograficamente.

Se o seu lsfor o GNU ls, você pode usar a -vopção de ordenar numericamente:

ls -1v

Ou:

ls -1vd -- *

Não é equivalente a sort -hporque 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 -vsã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-functionpega o nome do arquivo para classificar na $REPLYvariável e deve retornar para a mesma variável, algo que zshpode então ser classificado lexicograficamente (ou numericamente, se ntambé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)

( -Usendo a lsopçã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.20por 1.3exemplo:

$ 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 zshsó 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.

zshfaz 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 zshnú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 zshprecisã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 nyxmms2apenas 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

informação relacionada