Итак, я хочу воспроизвести несколько MP3 в консольном проигрывателе, который принимает имена файлов в качестве входных данных. У меня есть следующие файлы, как указано в ls -1 *
where *
get expanded моей оболочкой (zsh):
1 - Main title.mp3
10 - End title.mp3
2 - Intro.mp3
...
Но очевидно, что на самом деле я хочу, чтобы они были упорядочены следующим образом:
1 - Main title.mp3
2 - Intro.mp3
...
10 - End title.mp3
Какую магию расширения оболочки мне нужно применить, чтобы это стало возможным?
Я знаю, что мог бы добиться того же самого с помощью некоторых умных труб, sort -h
но это не совсем вариант.потому что я ленивая машинистка. Так что, если я не написал небольшой скрипт оболочки для добавления песни, я бы лучше сделал nyxmms2 add /path/to/dir/*.mp3
так, поэтому я и ищу способ сделать фильтрацию в расширении zsh... Кроме того, я хочу знать, возможно ли это, потому что это применимо и ко многим другим ситуациям — например, к файлам журналов или ревизиям или ...
решение1
Использоватьn
квалификатор glob.
print -lr -- *.mp3(n)
Вы можете изменить порядок сортировки по умолчанию, установивnumeric_glob_sort
вариант.
setopt numeric_glob_sort
print -lr -- *.mp3
Если вам нужен лексикографический порядок для одного шаблона, пока numeric_glob_sort
действует may, отмените n
квалификатор glob.
print -lr -- *(^n)
решение2
Одним из подходов может быть запуск вывода ls
через команду sort
, чтобы контролировать способ отображения вывода.
Вы можете использовать -h
(также известный как --human-numeric-sort
), который сортирует данные в удобной для восприятия форме.
$ ls | sort -h
1 - Main title.mp3
2 - Main title.mp3
10 - Main title.mp3
EDIT #1 - ответ на комментарий OP
Вышеприведенное можно оформить в виде псевдонима следующим образом:
$ alias lss="ls | sort -h"
Выполнение указанной выше команды тогда сократится до следующего:
$ lss
1 - Main title.mp3
2 - Main title.mp3
10 - Main title.mp3
Рекомендации
решение3
Вы можете изменить порядок сортировки в zsh
глобализации (см.ответ Жиля), но ls
в любом случае отсортирует свои аргументы, причем по умолчанию лексикографически.
Если вы ls
используете GNU ls
, вы можете использовать -v
опцию числовой сортировки:
ls -1v
Или:
ls -1vd -- *
Это не эквивалентно , sort -h
поскольку sort -h
сортирует такие вещи, как вывод du -h
, то есть когда 1.12G
больше 999M
, в то время как подстановочные квалификаторы ls -v
и предназначены для сортировки таких вещей, как номера версий (где 1.20 больше 1.4, например).zsh
(n)
Если вам нужна подстановка, которая понимает эти достаточные значения, вам придется написать для этого функцию сортировки zsh.
С помощью zsh можно определить порядок сортировки glob с помощью функции и использовать ее как *(o+that-function)
. that-function
принимает имя файла для сортировки в $REPLY
переменной и должен возвращать ту же самую переменную, которую zsh
затем можно отсортировать лексикографически (или численно, если n
также предоставлено).
Что-то вроде:
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))}
}
заменит все 1.1G на их значение (1181116006.4).
Который затем можно использовать как:
ls -1Ud -- *(no+h)
( -U
это опция GNU, ls
чтобы сказатьls
нетдля сортировки его аргументов).
Однако это не будет работать хорошо с числами с дробной частью, так как сортировка будет выполняться, например, 1.20
после :1.3
$ ls
1.20 1.3 3.1G 500M
$ ls -v1Ud -- *(no+h)
1.3
1.20
500M
3.1G
Для чего-то, что сортировало бы все виды десятичных чисел с плавающей точкой с необязательными суффиксами (например, -1e20M, 1E-20, 100k, 3000M), поскольку zsh
сортировка может выполняться только лексикографически или численно, ограниченная положительными десятичными целыми числами, нам понадобится функция для преобразования их либо в строки, которые сортируются лексикографически в том же порядке, либо в положительные десятичные целые числа, которые сортируются численно в том же порядке.
zsh
выполняет арифметику с плавающей точкой и десятичную арифметику с 64-битными числами, где это возможно, поэтому мы могли бы применить функцию с плавающей точкой, которая преобразует эти числа (или, по крайней мере, диапазон, поддерживаемый числами с zsh
плавающей точкой) в целое число от 0 до 2 63 . Использование функции логарифма может быть вариантом. Что-то вроде:
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)))))]}
}
Использовать как:
print -rl -- *(no+h)
Или, например, вернуться к числовой сортировке, чтобы различить 1000000000000000001 и 1000000000000000002 (которые имеют одинаковый логарифм с zsh
точностью до числа с плавающей точкой):
print -rl -- *(noe:h:on)
Тогда мы получаем нечто даже лучшее, чем 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
Теперь, что касается вашей конкретной проблемы nyxmms2, в дополнение к ответу Жиля, если вы ленивый печатающий, вы также можете определить это время каквыбор(вместо «упорядочивания») функция для музыкальных файлов, например:
m() [[ $REPLY == (#i)*.(mp3|ogg)(-.) ]]
nyxmms2 *Zep*(n+m)
Или используйте переменную:
m='.(#i)(mp3|ogg)(n-.)'
nyxmms2 *Zep*$~m
Или глобальный псевдоним:
alias -g @m='./*.(#i)(mp3|ogg)(n-.)'
nyxmms2 @m
Чтобы включить numericglobsort nyxmms2
только для, вы можете сделать следующее:
preexec() {[[ $1 = nyxmms2* ]] && setopt numericglobsort}
precmd setopt nonumericglobsort
решение4
Для этого вы всегда можете воспользоваться расширением оболочки.
nyxmms2 add $(ls /path/to/dir/*.mp3 | sort -n)
поскольку вы имеете дело с музыкой, вы можете создавать «плейлисты»
ls /path/to/album/or/song/*.mp3 | sort -n >> /path/to/playlist
nyxmms2 add < /path/to/playlist