66

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
0

8 Answers 8

56

⚠️ This answer is a little dated. Please check out the other answers, particularly those using aliases or ls -v.


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.

However, note that this will basically stop support for your actual locale across all locale-aware utilities.


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.

6
  • 2
    Setting LC_ALL="C" did the trick! Thanks for the quick response
    – clang1234
    Jul 13, 2012 at 1:20
  • 9
    Setting LC_ALL="C" will ls foreign language (e.g. Japanese) unicode filenames as ????????
    – ohho
    Jul 23, 2013 at 8:31
  • 1
    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, 2014 at 4:16
  • 2
    I think this answer is a little out of date. At the very least use C.UTF-8, as in @Faroul's answer, as the old non-Unicode variant will cause trouble for things like Python 3 output. But do note, as others have, that locale affects everything, not just ls, so setting the locale to C or C.UTF-8 will e.g. disable spell checking. So best to set your locale appropriately, e.g. to en_US.UTF-8, and go for a solution that only affects ls (like using aliases and the -v flag as in @VinceValenti's answer). Apr 26, 2020 at 13:43
  • thank you very much for ls -v
    – Luke
    Jul 1, 2020 at 6:58
43

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
  • 3
    This is the best answer here by far Mar 29, 2015 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, 2016 at 19:56
  • 2
    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, 2016 at 8:17
28

The ls(1) manpage lists:

-v natural sort of (version) numbers within text

This seems change how periods are sorted and does group dotfiles first. I have:

alias ls='ls -vAF'
alias ll='ls -l'

in my ~/.bashrc.

10

Setting

LC_ALL="C.UTF-8"

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

8
  • 3
    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, 2014 at 20:47
  • 1
    +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, 2014 at 4:16
  • 3
    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). Jun 7, 2015 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, 2018 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. Jul 9, 2018 at 16:09
1

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.

1

The following line shows (dot-)directories first and the (dot-)files. I had trouble to find out the right solution within the other answers so I wanted to clarify it:

ls -vAFl --group-directories-first

This shows

  • dot-dirs first
  • then other dirs (but case sensitive: first upper- then lower-case)
  • dot-files
  • non-dot files
1
  • 1
    As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Sep 29, 2022 at 17:28
0

ls -lvAX

-l : use a long listing format

-v : natural sort of (version) numbers within text

-A : do not list implied . and ..

-X : sort alphabetically by entry extension

-1

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.

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .