Як я можу змусити спочатку "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і перезапустив комп’ютер. На жаль, це нічого не змінило.

Відповіді:


11

OP був дуже близький до редагування /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.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.


звичайно, вам доведеться додати -a або -A, щоб побачити свої dotfiles, але якщо ви завжди хочете їх бачити, це має сенс робити в командному рядку, а не у вашому сценарії BASH
beandip

Блискуче! Дякую, це ідеально! Я щойно змінив файл, що належить root, тому не перевіряв ваш сценарій. Однак я думаю, що вам потрібно поставити подвійні лапки $@.
Sparhawk

хороший дзвінок - додано подвійні котирування
пн

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, .*'s розширення не включає .і .., тому це відповідає 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 не знаходиться в оточенні)
Stéphane Chazelas

Підлий (+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

+1 теж, але відповідно до відповіді StephenKitt, я не впевнений, яким чином я б легко використовував це у всіх випадках, тобто в псевдонімі чи функції. Наприклад, це доведеться змінити, якщо я хочу вказати конкретний каталог lsяк аргумент. (FWIW я використовую zsh, але це, мабуть, корисно для людей-
башмаків

-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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.