У меня есть куча каталогов, каждая из которых содержит кучу файлов. Обычно я могу перечислить все файлы с помощью ls */*.* но это всегда перечисляет их в соответствии с алфавитным порядком в каталогах, затем в алфавитном порядке в каждом каталоге. Так что это всегда будет выводить

dir1/file1.foo
dir1/file2.foo
...
dir2/file1.foo
dir2/file2.foo
...
...
DIRN /file1.foo
DIRN /file2.foo
...

Вместо этого я хотел бы вывести его так, чтобы каталоги были расположены в определенном порядке (например, в обратном порядке), но все файлы в каждом каталоге были расположены в обычном порядке, например:

DIRN /file1.foo
DIRN /file2.foo
...
...
dir1 /file1.foo
dir1 /file2.foo
...

Использование ls -r */*.* Не делает то, что я хочу, потому что он меняет порядок внутри каждого каталога, а также порядок самих каталогов. Я попытался использовать ls `ls -r` который делает то, что я хочу, для имен каталогов, в которых нет пробелов, но не будет работать для тех, которые делают (что, к сожалению, большинство из них). Если я вместо этого попытаюсь использовать ls "`ls -r`" то он выдаст то же самое, что и ls -r - список имен каталогов, но в обратном порядке. Как заставить bash делать то, что я хочу?

3 ответа3

1

Используя команду sort :

ls */* | sort -rst '/' -k1,1

с:

  • -t '/' чтобы изменить разделитель полей
  • -r сделать обратную сортировку
  • -s для обеспечения стабильности сортировки (другими словами, она не меняет порядок за пределами указанных столбцов
  • -k1,1 ограничить сортировку первым столбцом

Это предполагает, что вывод ls */* уже отсортирован (что и должно быть), в противном случае добавьте простой этап sort в середине.

0

через zsh скрипт

Как и в большинстве вещей в Linux/Unix, существует более одного способа сделать что-то. К счастью или круче, и ради чего это стоит, это еще один способ сделать то же самое.

#!/usr/bin/env zsh
Dirs=(*(/D))  # (/D) = /(only directories) D(include hidden or dot)
for D in ${(O)Dirs}  # (O) = reverse sort
do
    L=(${D}/*(ND))  # (ND) = N(in case the glob is empty) D(see above)
    [ ${#L} -eq 0 ] && { print "${D}/" ; continue }  # if empty glob
    print -l ${(o)L}  # (o) = normal sort
done

Команда print zsh -l выводит каждый элемент в отдельной строке.

Бросьте в D Глоб спецификатор , если вы не хотите , чтобы список скрытых файлов и каталогов.

0

Дополнение ответа @ xeniod (начинался как комментарий, но получался слишком длинным): согласно исходному требованию сортировки каталогов в обратном порядке и файлов в алфавитно-цифровом порядке:

$ ls -d */* | sort -s -t '/' -k1,1rn -k2,2

Или, если файлы / каталоги имеют более одной цифры, например, вместо dir1..dir9 , у вас также есть dir10, dir11, dir101,... и файлы file1..file10..file101... , вы можете отсортировать в качестве "номеров версий", используя опцию -V , вместо буквенно-цифровой сортировки (поддерживается только в сортировке GNU):

$ ls -d */* | sort -s -t '/' -k1,1rV -k2,2V

В идеале, однако, ваши каталоги и файлы должны иметь специальный префикс префикса (или разделять) полей, по которым вы хотите отсортировать, например, тире (" - "), например, dir-23/file-1.txt , dir-902/file-203.txt и т.д., Так что вы можете сортировать только по этим полям (не числовой текст после того, как число игнорируется):

$ ls -d */* | sort -s -t- -k2,2nr  -k3,3n

Ключевые моменты:

  • добавить несколько -k{begin,end} для сортировки столбцов между разделителями / отдельности, например, сортировать первый столбец как буквенно-цифровой, второй - как обратный-цифровой, третий - как "номера версий" и т. д.
  • Я добавил « -d » в « ls -d */* », чтобы содержимое каталога не отображалось в списке, что нарушит сортировку, если она существует. В качестве альтернативы, чтобы рассматривать только файлы, можно использовать find */ -maxdepth 1 -type f вместо ls .)
  • Обратите внимание, что вы действительно не заботитесь о «/» в своем роде, что обычно хорошо. Обратите внимание, что вы не можете иметь более одной опции -t {delim} в одной сортировке (например, -t '-' -k... -t '/'...)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .