Somewhere along the way I screwed up my ls command and now I get this ordering when running

$ ls -AhHl --color=auto
-rwxr-xr-x 1 clang clang  640 Mar  1 02:46 apple-touch-icon-precomposed.png
-rwxr-xr-x 1 clang clang  784 Jul 12 02:54 crossdomain.xml
-rwxr-xr-x 1 clang clang 1.2K Mar  1 02:46 favicon.ico
drwxr-xr-x 8 clang clang 4.0K Jul 12 23:50 .git
-rw-r--r-- 1 clang clang   17 Feb 29 19:48 .gitignore
-rwxr-xr-x 1 clang clang 1.4K Jul 12 02:54 humans.txt

What did I do that made ls ignore the dotfiles and instead order by first letter?

Output of locale:

$ locale
LANG=
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8
up vote 40 down vote accepted

Try adding

export LC_COLLATE="C"

in your dotfiles, or changing the LC_ALL assignment to:

export LC_ALL="C"

This controls the way sorting on character level works — while the default would be to sort dotfiles inline, this will make sort list dotfiles first.


To go further, quoting the GNU Coreutils manual (emphasis mine):

If you use a non-POSIX locale (e.g., by setting LC_ALL to en_US), then sort may produce output that is sorted differently than you're accustomed to.

In that case, set the LC_ALL environment variable to C. Note that setting only LC_COLLATE has two problems. First, it is ineffective if LC_ALL is also set. Second, it has undefined behavior if LC_CTYPE (or LANG, if LC_CTYPE is unset) is set to an incompatible value. For example, you get undefined behavior if LC_CTYPE is ja_JP.PCK but LC_COLLATE is en_US.UTF-8.

  • 2
    Setting LC_ALL="C" did the trick! Thanks for the quick response – clang1234 Jul 13 '12 at 1:20
  • 5
    Setting LC_ALL="C" will ls foreign language (e.g. Japanese) unicode filenames as ???????? – ohho Jul 23 '13 at 8:31
  • Note that by adding export LC_ALL="C" to your dotfiles you'll effectively lose support for your actual locale across all locale-aware utilities. While the printing problem that @ohho points out could be remedied with Faroul's answer, you'll introduce sorting problems: sorting will happen by byte value only, resulting in sorting that is (a) unexpectedly case-sensitive, and (b) invariably places accented chars. after all non-accented ones. – mklement0 Nov 3 '14 at 4:16

To avoid any system wide changes without real need, one can change only the way how ls works for the current user by adding the alias to the .bashrc:

alias ll='LC_COLLATE=C ls -alF'

This sorts dot files first, allows to properly handle (show and sort) "uncommon" character sets like cyrillic. The only culprit that the sorting will be case-sensitive.

Source: http://ubuntuforums.org/showthread.php?t=816753

  • 3
    This is the best answer here by far – Engineer Dollery Mar 29 '15 at 13:16
  • Beautiful. Much better than changing the system-wide configuration (which can cause you problems with some python modules). – Gui Ambros May 28 '16 at 19:56
  • This was the most helpful answer. Additionally, in an environment where LC_ALL is already set to something incompatible with sorting/hoisting dotfiles to the top of the ls listing, use alias ll='LC_ALL=C ls -alF' instead, because LC_COLLATE doesn't override LC_ALL. – matty Jul 6 '16 at 8:17

Setting

LC_ALL="C.UTF-8"

works fine for me - umlauts and "ls -la" lists dot-files first.

  • 2
    dot files are listed first, but now file names that starts with a uppercase letter are listed before those that starts with a lowercase. – Chnossos Aug 2 '14 at 20:47
  • +1 for coming closer than the accepted answer, but to summarize the limitations: the sorting will become case-sensitive, and foreign characters - while now printed correctly due to UTF-8 - won't be sorted correctly. – mklement0 Nov 3 '14 at 4:16
  • 2
    C.UTF-8 is an invalid locale, so locale reverts back to C. You still lose UTF-8 support. In fact, it's even worse since LC_ALL=C mostprograms display most multibyte characters correctly, but with LC_ALL=something_invalid some programs don't (like `ls). – Martin Tournoij Jun 7 '15 at 23:54
  • @MartinTournoij but if Stéphane Chazelas says otherwise about GNU systems (so presumably Debian and Linux in general), which is correct? – muru Jul 9 at 15:49
  • @muru I'm not sure, I guess you'll have to ask Stéphane? All I know is that locale seems to error out with LC_ALL=C.UTF-8: gist.github.com/Carpetsmoker/ef09b3734b29372939f97107413d7733 – that is on Arch Linux. – Martin Tournoij Jul 9 at 16:09

An off the wall idea

Disclaimer: This is going to be overkill for most of you. But I've been doing this since 1995 and I have the skills to make my world exactly how I want it. So, I why not?

I really like using different sorting methods with ls, especially -rt (which is sort by reverse modified time). So, I decided to try something crazy and use awk to do my sorting.

# save as ~/.ls.awk
# inpsired by http://superuser.com/questions/448291/how-can-i-make-ls-show-dotfiles-first

{
    if($1 == "total"){
        print $0
        next
    }
    # may need to adjust $9 to match your name column
    if(match($9, /^(\033\[[0-9]*m)*\./)) # optionally look past xterm highlighting like: ^[[34m
        df[++dd] = $0
    else
        nf[++nn] = $0
}
END{
    while (++d in df)
        print df[d]
    while (++n in nf)
        print nf[n]
}

Now instead of defining a bash alias, I define a bash function (because aliases can only append arguments at the end, but functions can use them anywhere)

ll(){ CLICOLOR_FORCE=1 ls -lhA $* | awk -f ~/.ls.awk; }

To see the results

Let's create some sample files:

for n in 4 .4 3 .3 2 .2 1 .1; do touch $n; sleep 1; done

Using plain ls

$ ls -lA
total 8
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .1
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .2
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .3
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .4
-rwxr-xr-x  1 bbronosky  staff  285 Nov 29 13:14 .ls.awk
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 1
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 2
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 3
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 4
$ ls -lArt

total 8
-rwxr-xr-x  1 bbronosky  staff  285 Nov 29 13:14 .ls.awk
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 4
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .4
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 3
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .3
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 2
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .2
-rwxr-xr-x  1 bbronosky  staff    0 Dec  1 00:25 1
-rw-r--r--  1 bbronosky  staff    0 Dec  1 00:25 .1

Using my function that filters with awk

$ ll
total 8
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .1
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .2
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .3
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .4
-rwxr-xr-x  1 bbronosky  staff   285B Nov 29 13:14 .ls.awk
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 1
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 2
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 3
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 4

$ ll -rt
total 8
-rwxr-xr-x  1 bbronosky  staff   285B Nov 29 13:14 .ls.awk
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .4
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .3
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .2
-rw-r--r--  1 bbronosky  staff     0B Dec  1 00:25 .1
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 4
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 3
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 2
-rwxr-xr-x  1 bbronosky  staff     0B Dec  1 00:25 1

You can see my implementation of this here https://github.com/RichardBronosky/dotfiles/commit/6170c0a9

What's most important about this is that it is a framework for tweaking your ls output. You can do anything you want with that awk filter. You might want it to be directories, then dotfiles, then everything else. Once you know how to handle your xterm colors, it's not too difficult. It's totally up to you.

Might try this in your .bashrc or /etc/bashrc file:

LS_OPTIONS='--color=tty -A -F -X -B -h -v -b -T 0 --group-directories-first';
export LS_OPTIONS;
alias ls='/bin/ls $LS_OPTIONS';

This assumes you're running a somewhat newer version of ls that takes "--group-directories-first" as an option. You can obviously tweak the LS options to your liking.

  • What does --group-directories-first have to do with “show dotfiles first”? – G-Man Dec 20 '17 at 6:11

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.