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 -h
pero 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/*.mp3
por 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_sort
opción.
setopt numeric_glob_sort
print -lr -- *.mp3
Si necesita orden lexicográfico para un patrón mientras numeric_glob_sort
puede estar vigente, niegue el n
calificador global.
print -lr -- *(^n)
Respuesta2
Un enfoque sería ejecutar la salida ls
a través del comando sort
para 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 zsh
globo (consulteLa respuesta de Gilles.), pero ls
ordenará sus argumentos de todos modos y, por defecto, lexicográficamente.
Si tu ls
es GNU ls
, puedes usar la -v
opción para ordenar numéricamente:
ls -1v
O:
ls -1vd -- *
No es equivalente a sort -h
porque sort -h
es ordenar cosas como la salida de du -h
, es decir, donde 1.12G
es mayor que 999M
, mientras que los calificadores globales de and ls -v
está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-function
toma el nombre del archivo para ordenar la $REPLY
variable y debe regresar a esa misma variable, algo que zsh
luego puede ordenar lexicográficamente (o numéricamente si n
tambié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)
( -U
siendo la ls
opció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.20
después, 1.3
por 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 zsh
solo 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.
zsh
hace 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 zsh
flotantes) 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 zsh
precisió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 nyxmms2
solo, 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