Bagaimana saya bisa membuat "ls" menunjukkan dotfile terlebih dahulu sementara tetap case-sensitive?

21

Buat file berikut dalam direktori.

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

lsPesanan default saya mengabaikan keberadaan titik-titik terkemuka, menggabungkannya dengan file-file lain.

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

Saya dapat mengubah LC_COLLATE untuk menempatkan dotfiles pertama.

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

Sayangnya ini membuat jenis urutan case-sensitive, yaitu Adan Bmendahului adan b. Apakah ada cara untuk mencetak dotfile terlebih dahulu sambil tetap case-sensitive ( Adan amendahului Bdan b)?

Sunting: mencoba mengubah LC_COLLATE

Tidak ada jawaban sejauh ini sepenuhnya meniru fungsi lsdengan mudah. Dapat dibayangkan, saya bisa membungkus beberapa dari mereka dalam suatu fungsi, tetapi ini harus menyertakan beberapa kode rinci tentang (misalnya) cara bekerja tanpa argumen vs memasok direktori sebagai argumen. Atau cara berurusan dengan -dbendera eksplisit .

Atau, saya pikir mungkin ada yang lebih baik LC_COLLATEuntuk digunakan. Namun, sepertinya saya tidak bisa melakukan itu. Saya sedang menggunakan LC_COLLATE="en_AU.UTF-8". Saya memeriksa /usr/share/i18n/locales/en_AU(walaupun saya tidak yakin apakah ini file yang tepat, karena saya tidak dapat melihat referensi apa pun UTF-8); Saya menemukan yang berikut ini.

LC_COLLATE
copy "iso14651_t1"
END LC_COLLATE

/usr/share/i18n/locales/iso14651_t1berisi copy "iso14651_t1_common". Akhirnya, /usr/share/i18n/locales/iso14651_t1_commonberisi

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

Saya menghapus baris ini, berlari sudo locale-gen, dan me-restart komputer saya. Sayangnya, ini tidak mengubah apa pun.

Sparhawk
sumber

Jawaban:

11

OP sangat dekat dengan pengeditan /usr/share/i18n/locales/iso14651_t1_common, tetapi triknya adalah tidak menghapus baris

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

melainkan untuk memodifikasinya

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

Mengapa ini berhasil?

The IGNOREpernyataan menentukan bahwa berhenti penuh (periode alias, atau karakter <U002E>) akan diabaikan ketika memesan kata abjad. Untuk membuat dotfile Anda menjadi yang utama, ubahlah IGNOREke simbol penyatuan yang ada sebelum semua karakter lainnya. Simbol yang disusun didefinisikan oleh garis-garis seperti

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

dan mereka diperintahkan oleh penampilan garis

<something-inside-angle-brackets>

Dalam salinan saya iso14651_t1_common, simbol collating tempat pertama adalah <RES-1>, yang muncul pada baris 3458. Jika file Anda berbeda, gunakan simbol collating mana yang dipesan terlebih dahulu.

Detail tentang pemesanan karakter dengan LC_COLLATE

<U002E>memiliki tiga IGNOREpernyataan karena surat dapat dibandingkan beberapa kali dalam kasus ikatan. Untuk memahami hal ini, pertimbangkan huruf kecil adan besar A(yang merupakan bagian dari sekelompok karakter yang benar-benar dibandingkan empat kali):

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

Memiliki beberapa putaran perbandingan memungkinkan file yang dimulai dengan "a" dan "A" untuk dikelompokkan bersama karena keduanya dibandingkan <a>pada saat pass pertama, dengan huruf berikutnya menentukan pemesanan. Jika semua huruf berikut ini sama (misalnya a.txtdan A.txt), lintasan ketiga akan a.txtdidahulukan karena simbol susun untuk huruf kecil <MIN>muncul di baris 3467, sebelum simbol susun untuk huruf besar <CAP>(baris 3488).

Menerapkan perubahan ini

Jika Anda ingin periode lebih dulu setiap kali program memesan surat menggunakan LC_COLLATE, Anda dapat memodifikasi iso14651_t1_commonseperti yang dijelaskan di atas dan membangun kembali file lokasi Anda. Tetapi jika Anda ingin membuat perubahan ini hanya ke lsdan tanpa akses root, Anda dapat menyalin file lokal asli ke direktori lain sebelum memodifikasinya.

Apa yang saya lakukan

Lokal default saya adalah en_US, jadi saya disalin en_US, iso14651_t1dan iso14651_t1_commonuntuk $HOME/path/to/new/locales. Di sana saya membuat perubahan di atas iso14651_t1_commondan berganti nama en_USmenjadi en_DOTFILE. Selanjutnya saya mengkompilasi lokal en_DOTFILE dengan

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

Untuk mengganti lspemesanan default , buat skrip BASH bernama ls:

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

simpan di suatu tempat yang muncul sebelumnya /usr/bindi jalur Anda, dan membuatnya dapat dieksekusi dengan chmod +x ls.

beandip
sumber
tentu saja, Anda harus menambahkan -a atau -A untuk melihat dotfile Anda, tetapi kecuali jika Anda selalu ingin melihatnya, masuk akal untuk melakukannya pada baris perintah, bukan pada skrip BASH Anda
beandip
Cemerlang! Terima kasih, ini sempurna! Saya baru saja memodifikasi file yang dimiliki oleh root, jadi saya tidak menguji skrip Anda. Namun, saya pikir Anda perlu menempatkan tanda kutip ganda di sekitar Anda $@.
Sparhawk
panggilan baik - tanda kutip ganda ditambahkan
beandip
11

Anda dapat menggunakan urutan shell bukan (yang mungkin tidak melibatkan lokal ini pemeriksaan order; bash, AT & T ksh, yash, tcshdan zshmemberikan hasil yang diharapkan, mkshdan dash. Tidak fishtampaknya untuk memberikan kasus agar tidak sensitif namun memberikan hasil yang berbeda ketika ada non-ASCII karakter):

ls -dUl -- .* *

Ini memberikan lsdaftar file yang eksplisit (dan direktori) ke daftar, dan menonaktifkan lspenyortiran ( -U, yang merupakan ekstensi GNU).

Ada beberapa peringatan, tergantung pada shell yang Anda gunakan.

  • Dengan zsh, nomatchopsi default akan menyebabkan perintah gagal jika direktori tidak berisi file tersembunyi dan tidak tersembunyi; Anda dapat menonaktifkan nomatchuntuk menghindari itu, tetapi yang lebih baik adalah melakukan set -o cshnullglobsebaliknya (dan perintah untuk gagal hanya jika tidak ada gumpalan cocok dengan di (t)cshatau awal kerang Unix).
  • Dengan zsh, pdkshdan turunannya serta fish, .*ekspansi tidak termasuk .dan .., jadi ini cocok ls -Al. Dengan kerang lain .dan ..disertakan sehingga cocok ls -al. Dalam kasus terakhir Anda harus mengubah pola globbing untuk mengecualikan .dan ..( ls -dUl -- ..?* .[!.]* *).
  • Kecuali dalam fish, (t)cshatau zsh, jika ada pola globbing yang tidak cocok dengan apa pun, lsakan menghasilkan pesan kesalahan; Anda dapat menghindari ini baik dengan menetapkan nullglobpilihan (dalam bashatau zshsetidaknya), atau dengan mengarahkan stderrke /dev/null( ls -dUl -- ..?* .[!.]* * 2>/dev/null). Jika Anda menggunakan nullglob, hati-hati terhadap perilaku mengejutkan yang berpotensi menyebabkan (lihat karakter Shell makan `?` ). fishberperilaku seperti bashdengan nomatchkecuali bahwa ketika interaktif, pesan peringatan akan dikeluarkan untuk setiap gumpalan yang tidak cocok.

(Terima kasih kepada Stéphane Chazelas untuk semua umpan baliknya!)

Stephen Kitt
sumber
Perhatikan bahwa tidak semua shell akan mengurutkan daftar menggunakan urutan susunan lokal. mkshdan dashmisalnya tidak akan memilah case-insensitive.
Stéphane Chazelas
1
Perhatikan bahwa -U(artinya tidak disortir) adalah ekstensi GNU. Beberapa lsimplementasi lain seperti FreeBSD memiliki -Utetapi tidak untuk daftar yang tidak disortir.
Stéphane Chazelas
Dengan GNU ls, Anda perlu --sebelumnya .*karena implementasi menerima opsi setelah argumen (kecuali POSIXLY_CORRECT ada di lingkungan)
Stéphane Chazelas
Sneaky (+1)! Namun, saya tidak yakin bagaimana saya akan menggunakan ini dengan mudah dalam semua kasus, yaitu dalam alias atau fungsi. Sebagai contoh, itu harus berubah jika saya ingin menentukan direktori tertentu lssebagai argumen.
Sparhawk
1
@PeterCordes [!.]benar. Lihat pubs.opengroup.org/onlinepubs/9699919799/utilities/… . Beberapa shell (paling?) Memungkinkan ^sebagai sinonim untuk !di gumpalan kelas karakter dinegasikan. Dalam hal apapun, saya lebih suka .[!.] .??* *yang sedikit lebih dapat dipahami daripada.[!.]* ..?* *
jrw32982 mendukung Monica
4

Anda bisa menggunakan dua lsperintah terpisah :

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

Berbeda dengan jawaban lain sejauh ini, pendekatan ini menampilkan file titik pertama yang menghindari .dan ..entri, kemudian entri yang tersisa dalam ls urutan abjad.

Jawaban @StephenKitt mungkin ditingkatkan meskipun untuk mencapai hasil yang sama:

$ ls -dUl ..?* .[^.]* * 2>/dev/null
Jlliagre
sumber
+1 juga, tetapi sesuai jawaban StephenKitt, saya tidak yakin bagaimana saya akan menggunakan ini dengan mudah dalam semua kasus, yaitu dalam alias atau fungsi. Sebagai contoh, itu harus berubah jika saya ingin menentukan direktori tertentu lssebagai argumen. (FWIW saya menggunakan zsh, tapi ini berguna untuk orang-orang bash, saya kira.)
Sparhawk
-2

Anda dapat bermain dengan opsi perintah ls . Coba ini:

# ls -laXr

Dimana:

-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
Rodrigo Calvo
sumber
Maaf, itu sepertinya tidak melakukan apa yang saya inginkan. The -Xflag macam oleh ekstensi setelah ., yang sama sekali berbeda. Juga, file-file tersebut dalam urutan abjad terbalik. Juga, sementara dotfile adalah yang pertama untuk contoh saya, itu tidak akan berfungsi dalam semua kasus (misalnya a.b c.d .a .c). Juga, Anda telah menggunakan -abukan -A.
Sparhawk