web-dev-qa-db-ja.com

大文字と小文字を区別せずに「ls」にドットファイルを最初に表示させるにはどうすればよいですか?

次のファイルをディレクトリに作成します。

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

I canchangeLC_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 你好嗎

残念ながら、これはソート順の大文字と小文字を区別します。つまり、ABabの前に置かれます。大文字と小文字を区別せずにドットファイルを最初に印刷する方法はありますか(AaBbに先行します)?

編集: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を実行し、コンピュータを再起動しました。残念ながら、これは何も変わりませんでした。

21
Sparhawk

OPは/usr/share/i18n/locales/iso14651_t1_commonの編集に非常に近かったが、トリックはdelete行ではない

<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>には3つのIGNOREステートメントがあります。同順位の場合、文字を複数回比較できるためです。これを理解するために、小文字のaと大文字のAを検討してください(これらは実際に4回比較される文字のグループの一部です)。

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

複数回の比較を行うと、「a」と「A」で始まるファイルをグループ化できます。これは、最初のパスで両方が<a>として比​​較され、次の文字が順序を決定するためです。次のすべての文字が同じである場合(例:a.txtA.txt)、小文字a.txtの照合記号が行に表示されるため、3番目のパスでは<MIN>が最初に配置されます。 3467、大文字の照合記号の前<CAP>(3488行目)。

この変更の実装

期間を最初にしたい場合毎回プログラムはLC_COLLATEを使用して手紙を注文します。上記のようにiso14651_t1_commonを変更して、場所ファイルを再構築できます。しかし、この変更をしたい場合onlylsに変更し、rootアクセスなしで、元のロケールファイルを変更する前に別のディレクトリにコピーできます。

私がしたこと

デフォルトのロケールはen_USなので、en_USiso14651_t1、およびiso14651_t1_common$HOME/path/to/new/localesにコピーしました。そこで、上記の変更をiso14651_t1_commonに加え、en_USen_DOTFILEに名前変更しました。次にen_DOTFILEロケールをコンパイルして

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

デフォルトのlsの順序を置き換えるには、lsというBASHスクリプトを作成します。

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

パスの/usr/binの前のどこかに保存し、chmod +x lsで実行可能にします。

11
beandip

代わりにシェルの並べ替え順序を使用できます(ロケールの照合順序は含まれない場合があります。bash、AT&T kshyashtcshzshは期待される結果を提供しますが、mkshおよびdashは提供しません。fishは大文字と小文字を区別しない順序を示しますが、ASCII以外の文字がある場合は結果が異なります) :

ls -dUl -- .* *

これにより、リストするファイル(およびディレクトリ)の明示的なリストがlsに与えられ、lsのソート(-U、GNU拡張子)が非アクティブになります)。

使用しているシェルによっては、いくつかの注意点があります。

  • zshでは、デフォルトのnomatchオプションを使用すると、ディレクトリに隠しファイルと非隠しファイルの両方が含まれていない場合、コマンドが失敗します。それを避けるためにnomatchを無効にすることもできますが、代わりにset -o cshnullglobを実行することをお勧めします(そして(t)cshまたは初期のUnixシェルのように、どのglobも一致しない場合にのみ失敗するコマンド) 。
  • zshpdkshとその派生物、およびfishを使用すると、.*の展開には...が含まれないため、これは一致します。 ls -Al。他のシェルでは、.および..が含まれているため、ls -alと一致します。後者の場合、.および..ls -dUl -- ..?* .[!.]* *)を除外するようにグロビングパターンを変更する必要があります。
  • fish(t)csh、またはzshを除いて、いずれかのグロビングパターンが何にも一致しない場合、lsはエラーメッセージを生成します。これを回避するには、nullglobオプションを設定するか(少なくともbashまたはzshで)、またはstderr/dev/nullにリダイレクトします( ls -dUl -- ..?* .[!.]* * 2>/dev/null)。 nullglobを使用する場合、原因となる可能性のある驚くべき動作に注意してください(「 シェルが「?」文字を食べる を参照)。 fishbashnomatchのように動作しますが、対話型の場合、一致しない各グロブに対して警告メッセージが発行されます。

(すべてのフィードバックに対して StéphaneChazelas に感謝します!)

11
Stephen Kitt

あなたは単に2つの別々の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
4
jlliagre