Как сделать так, чтобы «ls» сначала показывал точечные файлы, оставаясь без учета регистра?

21

Создайте следующие файлы в каталоге.

$ touch .a .b a b A B 你好嗎

Мой lsпорядок по умолчанию игнорирует наличие начальных точек, смешивая их с другими файлами.

$ ls -Al
total 0
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 A
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 B
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:06 你好嗎

Я могу изменить, LC_COLLATE чтобы поместить точечные файлы в первую очередь.

$ LC_COLLATE=C ls -Al
total 0
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 A
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 B
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:06 你好嗎

К сожалению, это делает порядок сортировки чувствительным к регистру, то есть Aи Bпредшествует aи b. Есть ли способ сначала напечатать точечные файлы, оставаясь без учета регистра ( Aи aпредшествовать Bи b)?

Изменить: попытка изменить LC_COLLATE

Ни один из ответов до сих пор полностью не повторяет функционал lsлегко. Возможно, я мог бы обернуть некоторые из них в функцию, но это должно было бы включать некоторый подробный код (например), как работать без аргументов, а не указывать каталог в качестве аргумента. Или как бороться с явным -dфлагом.

В качестве альтернативы я подумал, что может быть лучше LC_COLLATEиспользовать. Тем не менее, я не могу заставить эту работу. Я сейчас пользуюсь LC_COLLATE="en_AU.UTF-8". Я проверил /usr/share/i18n/locales/en_AU(хотя я не уверен, что это правильный файл, так как я не вижу ссылок на него UTF-8); Я нашел следующее.

LC_COLLATE
copy "iso14651_t1"
END LC_COLLATE

/usr/share/i18n/locales/iso14651_t1содержит copy "iso14651_t1_common". Наконец, /usr/share/i18n/locales/iso14651_t1_commonсодержит

 <U002E> IGNORE;IGNORE;IGNORE;<U002E> # 47 .

Я удалил эту строку, запустил sudo locale-genи перезагрузил компьютер. К сожалению, это ничего не изменило.

Sparhawk
источник

Ответы:

11

ОП был очень близок к редактированию /usr/share/i18n/locales/iso14651_t1_common, но хитрость не в том, чтобы удалить строку

<U002E> IGNORE;IGNORE;IGNORE;<U002E> # 47 .

а скорее, чтобы изменить его

<U002E> <RES-1>;IGNORE;IGNORE;<U002E> # 47 .

Почему это работает

В IGNOREоператорах указывается, что <U002E>при упорядочении слов в алфавитном порядке точка остановки (точка или символ ) будет игнорироваться. Чтобы ваши точечные файлы были на первом месте, измените IGNOREих на символ сортировки, который ставится перед всеми остальными символами. Символы сортировки определяются такими строками, как

collating-symbol <something-inside-angle-brackets>

и они упорядочены по внешнему виду линии

<something-inside-angle-brackets>

В моей копии iso14651_t1_commonсимвол сопоставления занимает первое место <RES-1>, которое появляется в строке 3458. Если файл отличается, используйте любой символ сопоставления, упорядоченный первым.

Подробности о порядке символов с помощью LC_COLLATE

<U002E>имеет три IGNOREутверждения, потому что буквы могут сравниваться несколько раз в случае связей. Чтобы понять это, рассмотрим строчные aи прописные буквы A(которые являются частью группы символов, которые на самом деле сравниваются четыре раза):

<U0061> <a>;<BAS>;<MIN>;IGNORE # 198 a
<U0041> <a>;<BAS>;<CAP>;IGNORE # 517 A

Наличие нескольких раундов сравнения позволяет группировать файлы, которые начинаются с «a» и «A», потому что оба сравниваются как <a>во время первого прохода, а следующая буква определяет порядок. Если все следующие буквы одинаковы (например, a.txtи A.txt), третий проход будет помещен a.txtпервым, потому что символ сопоставления для строчных букв <MIN>появляется в строке 3467, перед символом сопоставления для заглавных букв <CAP>(строка 3488).

Реализация этого изменения

Если вы хотите, чтобы период наступал первым каждый раз, когда программа заказывает буквы с использованием LC_COLLATE, вы можете изменить, iso14651_t1_commonкак описано выше, и перестроить файл местоположений. Но если вы хотите сделать это изменение только для lsкорневого доступа и без него, вы можете скопировать исходные файлы локали в другой каталог перед их изменением.

Что я сделал

Моя локаль по умолчанию является en_US, поэтому я скопировал en_US, iso14651_t1и iso14651_t1_commonв $HOME/path/to/new/locales. Там я внес вышеуказанное изменение iso14651_t1_commonи переименовал en_USв en_DOTFILE. Затем я скомпилировал локаль en_DOTFILE с

localedef -i en_DOTFILE -f UTF-8 -vc $HOME/path/to/new/locales/en_DOTFILE.UTF-8

Чтобы заменить lsпорядок по умолчанию , создайте скрипт BASH с именем ls:

#!/bin/bash
LOCPATH=$HOME/path/to/new/locales LANG=en_DOTFILE.UTF-8 ls "$@"

сохраните его в том месте, где он раньше находился /usr/binна вашем пути, и сделайте его исполняемым с chmod +x ls.

beandip
источник
конечно, вам нужно добавить -a или -A, чтобы увидеть ваши точечные файлы, но если вы не хотите всегда их видеть, имеет смысл делать это в командной строке, а не в вашем BASH-скрипте
beandip
Brilliant! Спасибо, это прекрасно! Я только что изменил файл, принадлежащий корню, поэтому я не проверял ваш скрипт. Тем не менее, я думаю, что вы должны поместить двойные кавычки вокруг вашего $@.
Sparhawk
хороший звонок - добавлены двойные кавычки
beandip
11

Вы можете использовать порядок сортировки командного интерпретатора вместо (который не может включать в себя параметры сортировки порядок локали; bash, AT & T ksh, yash, tcshи zshдают ожидаемые результаты, mkshи dash. Не fishкажется , чтобы дать регистрозависимости порядок , но дает разные результаты , когда Есть не-ASCII символы):

ls -dUl -- .* *

Это дает lsявный список файлов (и каталогов) для списка и деактивирует lsсортировку ( -Uкоторая является расширением GNU).

Есть несколько предостережений, в зависимости от используемой вами оболочки.

  • При zshиспользовании nomatchопции по умолчанию команда не будет выполнена, если каталог не содержит скрытых и не скрытых файлов; Вы могли бы отключить, nomatchчтобы избежать этого, но лучше было бы сделать это set -o cshnullglobвместо этого (и команда потерпела бы неудачу, только если ни один из глобусов не соответствует, как в (t)cshранних или ранних оболочках Unix).
  • С zsh, pdkshи его производная и fish, .*расширение не включает .и .., так что это соответствует ls -Al. С другими снарядами .и ..включены, чтобы он соответствовал ls -al. В последнем случае вам нужно изменить шаблоны сглаживания, чтобы исключить .и ..( ls -dUl -- ..?* .[!.]* *).
  • За исключением случаев fish, (t)cshили zsh, если какой-либо из шаблонов слияния не совпадает с чем-либо, lsвыдаст сообщение об ошибке; Вы можете избежать этого, установив nullglobпараметр (в bashили zshпо крайней мере), или перенаправив stderrна /dev/null( ls -dUl -- ..?* .[!.]* * 2>/dev/null). Если вы используете nullglob, обратите внимание на потенциально удивительное поведение, которое вызывает (см. Shell поедает символы `?` ). fishведет себя как bashс тем nomatchисключением, что в интерактивном режиме выдается предупреждающее сообщение для каждого глобуса, который не соответствует.

(Спасибо Стефану Шазеласу за все отзывы!)

Стивен Китт
источник
Обратите внимание, что не все оболочки будут сортировать список, используя порядок сопоставления локали. mkshи, dashнапример, не будет сортировать без учета регистра.
Стефан Шазелас
1
Обратите внимание, что -U(что означает несортированный) является расширением GNU. У некоторых других lsреализаций, таких как FreeBSD, есть, -Uно это не для несортированного списка.
Стефан Шазелас
С GNU lsвам нужно --до этого, так .*как эта реализация принимает параметры после аргументов (если только POSIXLY_CORRECT не находится в среде)
Стефан Шазелас
Подлый (+1)! Тем не менее, я не уверен, как бы я использовал это легко во всех случаях, то есть в псевдониме или функции. Например, он должен измениться, если я хочу указать конкретный каталог lsв качестве аргумента.
Sparhawk
1
@PeterCordes [!.]правильно. См. Pubs.opengroup.org/onlinepubs/9699919799/utilities/… . Некоторые (большинство?) Оболочки допускают использование ^в качестве синонимов !в глобусах класса символов с отрицанием. В любом случае, я предпочитаю .[!.] .??* *быть немного более понятным, чем.[!.]* ..?* *
jrw32982 поддерживает Монику
4

Вы можете просто использовать две отдельные lsкоманды:

$ ls -dl ..?* .[^.]* 2>/dev/null ; ls -dl *
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 .a
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 .b
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 a
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 A
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 b
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 B
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 你好嗎

В отличии от других ответов до сих пор, этот подход показывает дот файлов первой Избегая .и ..записи, затем остальные элементы в ls алфавитном порядке.

Ответы @StephenKitt могут быть улучшены, хотя для достижения того же результата:

$ ls -dUl ..?* .[^.]* * 2>/dev/null
jlliagre
источник
+1 тоже, но согласно ответу StephenKitt, я не уверен, как бы я использовал это легко во всех случаях, то есть в псевдониме или функции. Например, он должен измениться, если я хочу указать конкретный каталог lsв качестве аргумента. (FWIW я использую zsh, но это полезно для bash-людей, я полагаю.)
Sparhawk
-2

Вы можете играть с опциями команды ls . Попробуй это:

# ls -laXr

Где:

-l     use a long listing format
-a, --all
              do not ignore entries starting with .
-X     sort alphabetically by entry extension
-r, --reverse
              reverse order while sorting
Родриго Кальво
источник
Извините, похоже, это не то, что я хочу. -XФлаг сортирует расширение после того ., который полностью отличается. Кроме того, файлы в обратном алфавитном порядке. Кроме того, хотя точечные файлы являются первыми для моего примера, они не будут работать во всех случаях (например a.b c.d .a .c). Кроме того, вы использовали -aвместо -A.
Sparhawk