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

3

Então, eu quero tocar alguns MP3s em um player de console que leva nomes de arquivos como entradas. Eu tenho os seguintes arquivos, como fornecido por ls -1 * onde * get expandido 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

Qual mágica de expansão de shell eu preciso para fazer isso?

Eu sei que poderia obter a mesma coisa com alguns pipes inteligentes e sort -h , mas isso não é realmente uma opção porque eu sou um datilógrafo preguiçoso . Então, a menos que eu tenha escrito um pequeno shell script para adicionar música, eu prefiro fazer nyxmms2 add /path/to/dir/*.mp3 , então por que eu estou olhando como fazer a filtragem dentro da expansão do zsh ... Além disso, eu quero saber se isso é possível porque aplica-se a muitas outras situações também - por exemplo, arquivos de log ou revisões ou ...

    
por Sardathrion 26.04.2013 / 14:53

4 respostas

4

Use o qualificador de glob n .

print -lr -- *.mp3(n)

Você pode alterar a ordem de classificação padrão definindo a opção numeric_glob_sort .

setopt numeric_glob_sort
print -lr -- *.mp3

Se você precisar de ordem lexicográfica para um padrão enquanto numeric_glob_sort estiver em vigor, negue o qualificador n glob.

print -lr -- *(^n)
    
por 27.04.2013 / 03:39
3

Uma abordagem seria executar a saída de 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.

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

EDIT # 1 - respondendo ao comentário do OP

Os itens acima podem ser agrupados em um alias assim:

$ alias lss="ls | sort -h"

A execução do comando acima seria reduzida a isso:

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

Referências

por 26.04.2013 / 15:16
2

Você pode alterar a ordem de classificação em zsh globbing (consulte a resposta de Gilles ), mas ls classificará seus argumentos de qualquer maneira e, por padrão, lexicograficamente.

Se o seu ls é o GNU ls , você pode usar a opção -v para 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 ls -v e zsh s% Os qualificadores(n) globbing são voltados para classificar coisas como números de versão (onde 1.20 é maior que 1.4 por exemplo).

Se você quiser um globbing que entenda esses bastos, você precisaria escrever uma função zsh sort para isso.

Com zsh, você pode definir a ordem de classificação glob com uma função e usá-la como *(o+that-function) . that-function pega o nome do arquivo para classificar na variável $REPLY e deve retornar para a mesma variável, algo que zsh pode ordenar 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))}
}

substituirá todos os 1.1G pelo seu valor (1181116006.4).

Que você pode usar como:

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

( -U sendo a opção ls do GNU para informar ls não para ordenar seus argumentos).

Isso não funcionará bem, no entanto, com números com uma parte fracionária, pois classificaria 1.20 após 1.3 , por exemplo:

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

Para algo que classifica todos os tipos de números decimais flutuantes com sufixos opcionais (como -1e20M, 1E-20, 100k, 3000M), porque zsh só pode classificar lexicograficamente ou numericamente limitado a inteiros decimais positivos, precisa de uma função para convertê-los em cadeias de caracteres que ordenem lexicograficamente na mesma ordem ou números inteiros decimais positivos que classifiquem numericamente na mesma ordem.

zsh faz aritmética decimal e de ponto flutuante 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 floats) em um 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, para retornar à classificação numérica para diferenciar 100000000000000001 e 100000000000000002 por exemplo (que possuem o mesmo logaritmo com zsh float precision):

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

Em seguida, 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, eu sou um digitador preguiçoso, você também pode definir esse tempo como uma função seleção (em vez de "pedido") para música arquivos, 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 o numericglobsort apenas para nyxmms2 , você pode:

preexec() {[[ $1 = nyxmms2* ]] && setopt numericglobsort}
precmd setopt nonumericglobsort
    
por 27.04.2013 / 20:13
1

você sempre pode usar a expansão do shell para fazer isso.

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

como você está lidando com música, pode criar "listas de reprodução"

ls /path/to/album/or/song/*.mp3 | sort -n >> /path/to/playlist
nyxmms2 add < /path/to/playlist
    
por 26.04.2013 / 15:28

Tags