Create the following files in a directory.
$ touch .a .b a b A B 你好嗎
My default ls
order ignores the presence of leading dots, intermingling them with the other files.
$ 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 can change LC_COLLATE
to put the dotfiles first.
$ 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 你好嗎
Unfortunately this makes the sort order case-sensitive, i.e. A
and B
precede a
and b
. Is there a way to print dotfiles first while staying case-insensitive (A
and a
precede B
and b
)?
Edit: attempting to modify LC_COLLATE
None of the answers so far fully replicate the functionality of ls
easily. Conceivably, I could wrap some of them in a function, but this would have to include some detailed code on (e.g.) how to work with no argument vs. supplying a directory as an argument. Or how to deal with an explicit -d
flag.
Alternatively, I thought that maybe there could be a better LC_COLLATE
to use. However, I can't seem to make that work. I'm currently using LC_COLLATE="en_AU.UTF-8"
. I checked /usr/share/i18n/locales/en_AU
(although I'm not sure if this is the right file, as I can't see any reference to UTF-8
); I found the following.
LC_COLLATE
copy "iso14651_t1"
END LC_COLLATE
/usr/share/i18n/locales/iso14651_t1
contains copy "iso14651_t1_common"
. Finally, /usr/share/i18n/locales/iso14651_t1_common
contains
<U002E> IGNORE;IGNORE;IGNORE;<U002E> # 47 .
I deleted this line, ran sudo locale-gen
, and restarted my computer. Unfortunately, this changed nothing.
Best Answer
OP was very close with editing
/usr/share/i18n/locales/iso14651_t1_common
, but the trick is not to delete the linebut rather to modify it to
Why this works
The
IGNORE
statements specify that the full stop (aka period, or character<U002E>
) will be ignored when ordering words alphabetically. To make your dotfiles come first, changeIGNORE
to a collating symbol that comes before all other characters. Collating symbols are defined by lines likeand they are ordered by the appearance of the line
In my copy of
iso14651_t1_common
, the first-place collating symbol is<RES-1>
, which appears on line 3458. If you file is different, use whichever collating symbol is ordered first.Details about character ordering with LC_COLLATE
<U002E>
has threeIGNORE
statements because letters can be compared multiple times in case of ties. To understand this, consider lowercasea
and uppercaseA
(which are part of a group of characters that actually get compared four times):Having multiple rounds of comparison allow files that start with "a" and "A" to be grouped together because both are compared as
<a>
during the first pass, with the next letter determining the ordering. If all of the following letters are the same (e.g.a.txt
andA.txt
), the third pass will puta.txt
first because the collating symbol for lowercase letters<MIN>
appears on line 3467, before the collating symbol for uppercase letters<CAP>
(line 3488).Implementing this change
If you want the period to come first every time a program orders letters using
LC_COLLATE
, you can modifyiso14651_t1_common
as described above and rebuild your locations file. But if you want to make this change only tols
and without root access, you can copy the original locale files to another directory before modifying them.What I did
My default locale is en_US, so I copied
en_US
,iso14651_t1
, andiso14651_t1_common
to$HOME/path/to/new/locales
. There I made the abovementioned change toiso14651_t1_common
and renameden_US
toen_DOTFILE
. Next I compiled the en_DOTFILE locale withTo replace the default
ls
ordering, make a BASH script calledls
:save it somewhere that appears before
/usr/bin
on your path, and make it executable withchmod +x ls
.