Ampliación con números en formato legible por humanos.

Ampliación con números en formato legible por humanos.

Entonces, quiero reproducir algunos MP3 en un reproductor de consola que acepte nombres de archivos como entradas. Tengo los siguientes archivos, según lo indicado por ls -1 *dónde *mi Shell (zsh) los expande:

1 - Main title.mp3
10 - End title.mp3
2 - Intro.mp3 
...

Pero claramente, la forma en que realmente quiero que se ordenen es así:

1 - Main title.mp3
2 - Intro.mp3 
...
10 - End title.mp3

¿Qué magia de expansión de caparazón necesito para que sea así?

Sé que podría conseguir lo mismo con algunas pipas inteligentes, sort -hpero esa no es realmente una opción.porque soy un mecanógrafo perezoso. Entonces, a menos que haya escrito un pequeño script de shell para agregar una canción, prefiero hacerlo, nyxmms2 add /path/to/dir/*.mp3por eso estoy buscando cómo hacer el filtrado dentro de la expansión de zsh... Además, quiero saber si esto es posible porque se aplica a muchas otras situaciones también, por ejemplo, archivos de registro o revisiones o...

Respuesta1

Utilizar eln calificador global.

print -lr -- *.mp3(n)

Puede cambiar el orden de clasificación predeterminado configurando elnumeric_glob_sortopción.

setopt numeric_glob_sort
print -lr -- *.mp3

Si necesita orden lexicográfico para un patrón mientras numeric_glob_sortpuede estar vigente, niegue el ncalificador global.

print -lr -- *(^n)

Respuesta2

Un enfoque sería ejecutar la salida lsa través del comando sortpara controlar cómo se muestra la salida.

Puede utilizar -h(también conocido como --human-numeric-sort) que clasifica las cosas en forma legible por humanos.

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

EDITAR #1 - abordar el comentario de OP

Lo anterior se puede encapsular en un alias así:

$ alias lss="ls | sort -h"

La ejecución del comando anterior se reduciría a esto:

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

Referencias

Respuesta3

Puede cambiar el orden de clasificación en zshglobo (consulteLa respuesta de Gilles.), pero lsordenará sus argumentos de todos modos y, por defecto, lexicográficamente.

Si tu lses GNU ls, puedes usar la -vopción para ordenar numéricamente:

ls -1v

O:

ls -1vd -- *

No es equivalente a sort -hporque sort -hes ordenar cosas como la salida de du -h, es decir, donde 1.12Ges mayor que 999M, mientras que los calificadores globales de and ls -vestán orientados a ordenar cosas como números de versión (donde 1.20 es mayor que 1.4, por ejemplo).zsh(n)

Si desea un globbing que entienda eso es suficiente, necesitará escribir una función de clasificación zsh para eso.

Con zsh, puede definir el orden de clasificación global con una función y usarlo como *(o+that-function). that-functiontoma el nombre del archivo para ordenar la $REPLYvariable y debe regresar a esa misma variable, algo que zshluego puede ordenar lexicográficamente (o numéricamente si ntambién se proporciona).

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))}
}

Reemplazaría todos los 1.1G a su valor (1181116006.4).

Que luego puedes usar como:

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

( -Usiendo la lsopción GNU para contarls nopara ordenar sus argumentos).

Sin embargo, eso no funcionará bien con números con una parte fraccionaria, ya que se ordenaría 1.20después, 1.3por ejemplo:

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

Para algo que pueda ordenar todo tipo de números flotantes decimales con suficientes opcionales (como -1e20M, 1E-20, 100k, 3000M), porque zshsolo puede ordenar lexicográfica o numéricamente limitado a enteros decimales positivos, necesitaríamos una función para convertir esos en cadenas que se clasifican lexicográficamente en el mismo orden o en enteros decimales positivos que se clasifican numéricamente en el mismo orden.

zshhace aritmética de punto flotante y decimal con números de 64 bits cuando estén disponibles, por lo que podríamos aplicar una función de punto flotante que convierta esos números (o al menos el rango admitido por zshflotantes) en un número entero de 0 a 2 63 . Usar la función logaritmo podría ser una opción. 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 utilizado como:

print -rl -- *(no+h)

O bien, para recurrir a la clasificación numérica para diferenciar 100000000000000001 y 100000000000000002, por ejemplo (que tienen el mismo logaritmo con zshprecisión flotante):

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

Entonces, obtenemos algo incluso mejor 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

Ahora, para tu problema específico de nyxmms2, para complementar la respuesta de Gilles, si eres un mecanógrafo vago, también puedes definir esta vez unselección(en lugar de "ordenar") función para archivos de música, como:

m() [[ $REPLY == (#i)*.(mp3|ogg)(-.) ]]

nyxmms2 *Zep*(n+m)

O use una variable:

m='.(#i)(mp3|ogg)(n-.)'
nyxmms2 *Zep*$~m

O un alias global:

alias -g @m='./*.(#i)(mp3|ogg)(n-.)'
nyxmms2 @m

Para activar numericglobsort nyxmms2solo, puedes hacer:

preexec() {[[ $1 = nyxmms2* ]] && setopt numericglobsort}
precmd setopt nonumericglobsort

Respuesta4

Siempre puedes usar la expansión de Shell para hacer esto.

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

Como se trata de música, puedes crear "listas de reproducción".

ls /path/to/album/or/song/*.mp3 | sort -n >> /path/to/playlist
nyxmms2 add < /path/to/playlist

información relacionada