Jak sprawić, by „ls” wyświetlał pliki kropkowe jako pierwszy bez rozróżniania wielkości liter?


21

Utwórz następujące pliki w katalogu.

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

Moja domyślna lskolejność ignoruje obecność wiodących kropek, mieszając je z innymi plikami.

$ 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 你好嗎

I może zmienić LC_COLLATE umieścić dotfiles pierwszy.

$ 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 你好嗎

Niestety powoduje to, że w kolejności sortowania rozróżniana jest wielkość liter, tzn. AI Bpoprzedzają ai b. Czy istnieje sposób, aby najpierw wydrukować pliki kropkowe bez rozróżniania wielkości liter ( Ai apoprzedzać Bi b)?

Edycja: próba modyfikacji LC_COLLATE

Żadna z dotychczasowych odpowiedzi nie w pełni powiela funkcjonalność lsłatwego. Możliwe, że mógłbym zawinąć niektóre z nich w funkcję, ale musiałoby to zawierać szczegółowy kod dotyczący (np.) Pracy bez argumentu w porównaniu z podaniem katalogu jako argumentu. Lub jak radzić sobie z wyraźną -dflagą.

Alternatywnie myślałem, że może być lepszy LC_COLLATEw użyciu. Jednak nie wydaje mi się, żeby to działało. Obecnie używam LC_COLLATE="en_AU.UTF-8". Sprawdziłem /usr/share/i18n/locales/en_AU(chociaż nie jestem pewien, czy jest to właściwy plik, ponieważ nie widzę żadnych odniesień do UTF-8); Znalazłem następujące.

LC_COLLATE
copy "iso14651_t1"
END LC_COLLATE

/usr/share/i18n/locales/iso14651_t1zawiera copy "iso14651_t1_common". Wreszcie /usr/share/i18n/locales/iso14651_t1_commonzawiera

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

Usunąłem tę linię, uruchomiłem sudo locale-geni ponownie uruchomiłem komputer. Niestety nic to nie zmieniło.

Odpowiedzi:


11

OP był bardzo blisko edycji /usr/share/i18n/locales/iso14651_t1_common, ale sztuczką nie jest usunięcie linii

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

ale raczej zmodyfikować go do

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

Dlaczego to działa

Te IGNOREoświadczenia określić, że kropkę (aka okres, lub postaci <U002E>) będą ignorowane przy zamawianiu słowa alfabetycznie. Aby Twoje pliki dot były na pierwszym miejscu, zmień IGNOREna symbol zestawiający, który pojawia się przed wszystkimi innymi znakami. Symbole zestawiania są zdefiniowane przez linie podobne

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

i są uporządkowane według wyglądu linii

<something-inside-angle-brackets>

W mojej kopii iso14651_t1_commonpierwszym symbolem zestawiania jest <RES-1>, który pojawia się w wierszu 3458. Jeśli plik jest inny, użyj dowolnego z tych symboli, który jest uporządkowany jako pierwszy.

Szczegóły dotyczące porządkowania znaków za pomocą LC_COLLATE

<U002E>ma trzy IGNOREstwierdzenia, ponieważ litery można porównywać wiele razy w przypadku powiązań. Aby to zrozumieć, rozważ małe ai wielkie litery A(które są częścią grupy znaków, które faktycznie są porównywane cztery razy):

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

Posiadanie wielu rund porównania pozwala grupować pliki zaczynające się od „a” i „A”, ponieważ oba są porównywane jak <a>podczas pierwszego przejścia, a kolejna litera określa kolejność. Jeśli wszystkie następujące litery są takie same (np. a.txtI A.txt), trzecie przejście ustawi się jako a.txtpierwsze, ponieważ symbol zestawiania małych liter <MIN>pojawia się w linii 3467, przed symbolem zestawiania wielkich liter <CAP>(linia 3488).

Wdrażanie tej zmiany

Jeśli chcesz, aby okres był na pierwszym miejscu za każdym razem, gdy program zamawia litery za pomocą LC_COLLATE, możesz zmodyfikować iso14651_t1_commonzgodnie z powyższym opisem i odbudować plik lokalizacji. Ale jeśli chcesz wprowadzić tę zmianę tylko do lsi bez dostępu użytkownika root, możesz skopiować oryginalne pliki ustawień regionalnych do innego katalogu przed ich modyfikacją.

Co ja zrobiłem

Moja domyślne locale pl, więc skopiowane en_US, iso14651_t1i iso14651_t1_commondo $HOME/path/to/new/locales. Tam dokonałem wyżej wymienionej zmiany iso14651_t1_commoni zmieniłem nazwę en_USna en_DOTFILE. Następnie skompilowałem ustawienia narodowe en_DOTFILE

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

Aby zastąpić domyślne lsporządkowanie, utwórz skrypt BASH o nazwie ls:

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

zapisz go w miejscu, które pojawia się wcześniej /usr/binna twojej ścieżce, i uruchom go za pomocą chmod +x ls.


Oczywiście, trzeba będzie dodać -a lub -A, aby zobaczyć swoje dotfiles, ale jeśli nie zawsze chcą je zobaczyć, warto to zrobić w linii poleceń, a nie w skrypcie bash
beandip

Znakomity! Dziękuję, to jest idealne! Właśnie zmodyfikowałem plik będący własnością roota, więc nie przetestowałem twojego skryptu. Myślę jednak, że musisz umieścić podwójne cudzysłowy wokół siebie $@.
Sparhawk

dobre połączenie - dodano podwójne cytaty
beandip

11

Można użyć porządek powłoce zamiast (która nie może obejmować lokalna sortowania zamówienie; bash, AT & T ksh, yash, tcshi zshdać oczekiwanych rezultatów, mksha dash. Nie fishwydaje się, aby dać wielkość liter ma znaczenie kolejność ale daje różne wyniki, gdy istnieją non-ASCII postacie):

ls -dUl -- .* *

Daje lsto jawną listę plików (i katalogów) do wyświetlenia, i dezaktywuje lssortowanie ( -Uktóre jest rozszerzeniem GNU).

Jest kilka ostrzeżeń, w zależności od używanej powłoki.

  • Z zshdomyślna nomatchopcja spowoduje polecenia się nie powiedzie, jeśli katalog nie zawiera zarówno ukryte i bez ukrytych plików; możesz wyłączyć, nomatchaby tego uniknąć, ale lepiej byłoby set -o cshnullglobzamiast tego zrobić (a polecenie zakończyło się niepowodzeniem tylko wtedy, gdy żadna z globusów nie pasuje jak w (t)cshpowłokach wczesnych lub uniksowych).
  • Z zsh, pdkshjego pochodna i fish, .*rozszerzenie nie obejmuje .i .., więc to pasuje ls -Al. Z innymi powłokami .i ..są dołączone, więc pasuje ls -al. W tym drugim przypadku należy zmienić wzorce globowania, aby wykluczyć .i ..( ls -dUl -- ..?* .[!.]* *).
  • Z wyjątkiem fish, (t)cshlub zsh, jeśli którykolwiek z wzorców globowania nie pasuje do niczego, lswyświetli komunikat o błędzie; możesz tego uniknąć, ustawiając nullglobopcję (w bashlub zshprzynajmniej), lub przekierowując stderrna /dev/null( ls -dUl -- ..?* .[!.]* * 2>/dev/null). Jeśli używasz nullglob, uważaj na potencjalnie zaskakujące zachowanie, które powoduje (zobacz Shell jedzący znaki `?` ). fishzachowuje się tak, jak bashz nomatchtym wyjątkiem, że gdy jest interaktywny, zostanie wyświetlony komunikat ostrzegawczy dla każdego globu, który nie pasuje.

(Podziękowania dla Stéphane'a Chazelasa za wszystkie opinie!)


Zauważ, że nie wszystkie powłoki posortują listę według kolejności sortowania w ustawieniach regionalnych. mkshi dashna przykład nie będzie sortować bez rozróżniania wielkości liter.
Stéphane Chazelas

1
Zauważ, że -U(to znaczy nieposortowane) jest rozszerzeniem GNU. Niektóre inne lsimplementacje, takie jak FreeBSD, mają, -Uale nie jest to nieposortowana lista.
Stéphane Chazelas

W GNU lspotrzebujesz --wcześniej, .*ponieważ implementacja akceptuje opcje po argumentach (chyba, że ​​POSIXLY_CORRECT znajduje się w środowisku)
Stéphane Chazelas

Podstępny (+1)! Nie jestem jednak pewien, jak z łatwością skorzystam z tego we wszystkich przypadkach, tj. W aliasie lub funkcji. Na przykład musiałoby się to zmienić, jeśli chcę podać konkretny katalog lsjako argument.
Sparhawk

1
@PeterCordes [!.]jest poprawny. Zobacz pubs.opengroup.org/onlinepubs/9699919799/utilities/… . Niektóre (najbardziej?) Powłoki pozwalają ^na używanie jako synonimów !w negowanych globach klas postaci. W każdym razie wolę .[!.] .??* *być nieco bardziej zrozumiały niż.[!.]* ..?* *
jrw32982 obsługuje Monikę

4

Możesz po prostu użyć dwóch osobnych lspoleceń:

$ 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 你好嗎

W przeciwieństwie do innych dotychczasowych odpowiedzi, to podejście wyświetla najpierw pliki kropek, unikając wpisów .i .., a następnie pozostałych wpisów w ls kolejności alfabetycznej.

Odpowiedź @StephenKitt może zostać ulepszona, aby osiągnąć ten sam wynik:

$ ls -dUl ..?* .[^.]* * 2>/dev/null

+1 również, ale zgodnie z odpowiedzią StephenKitt nie jestem pewien, jak z łatwością skorzystam z tego we wszystkich przypadkach, tj. W aliasie lub funkcji. Na przykład musiałoby się to zmienić, jeśli chcę podać konkretny katalog lsjako argument. (FWIW Używam zsh, ale przypuszczam, że jest to przydatne dla bash-people).
Sparhawk

-2

Możesz grać z opcjami polecenia ls . Spróbuj tego:

# ls -laXr

Gdzie:

-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

Przepraszam, to nie wydaje się robić tego, czego chcę. -XFlaga sortuje przez rozszerzenie od wyprodukowania ., który jest zupełnie inny. Ponadto pliki są w odwrotnej kolejności alfabetycznej. Ponadto, mimo że pliki kropkowe są pierwsze w moim przykładzie, nie będzie działać we wszystkich przypadkach (np a.b c.d .a .c.). Ponadto użyłeś -azamiast -A.
Sparhawk
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.