1

I'd like to have natural sorting of numbers, but capitalized files/dirs not sorted at the top. Is that possible?

Currently ls -lv produces:

FOO/
bar/
ZEBRA.x
foo.x
foo-1.x
foo-2.x
foo-10.x

I messed around with |sort ... but (1) nothing I tried worked and (2) it removed --color=auto from my ls command. I'm sure there's a fix for the color, but I have no idea what it is.

EDIT

In my testing, LC_COLLATE=C ls -l does the same thing as ls -lv.

Jeff
  • 796
  • You can force color with --color=always , but you might want to focus your question on the sorting (since |sort didn't fix anything). – Jeff Schaller Feb 07 '22 at 14:28

2 Answers2

2

You could always use zsh's numericglobsort or n glob qualifier instead.

$ locale title
English locale for Britain
$ print -rC1 -- *(Nn)
bar
FOO
foo-1.x
foo-2.x
foo-10.x
foo.x
ZEBRA.x
$ () { local LC_COLLATE=C; print -rC1 -- *(Nn); }
FOO
ZEBRA.x
bar
foo-1.x
foo-2.x
foo-10.x
foo.x

With GNU ls:

ls -U -ld --color -- *(n)

For ls not to sort (and list files in the order they were given by zsh's glob expansion).

If your locale's sort order is case sensitive like in the C locale, you can also do:

$ locale title
ISO/IEC 14652 i18n FDCC-set
$ print -rC1 -- *(Nnoe['REPLY=$REPLY:l'])
bar
FOO
foo-1.x
foo-2.x
foo-10.x
foo.x
ZEBRA.x

Were we use the oe glob qualifier to rewrite the names to lower case for ordering by evaluating the REPLY=$REPLY:l expression.

With GNU sort, -V (for version sort) can be combined with -f (case insensitive matching), but that assumes file names don't contain newline characters, and that only works for ASCII letters:

$ ls | LC_COLLATE=C sort -Vf
bar
ETE
FOO
foo.x
foo-1.x
foo-2.x
foo-10.x
ZEBRA.x
Á
ÉTÉ
á
été
0

Sorting in ls depends on your locale settings, however, unfortunately this is not considered when using ls -v and sort -V.

Check LC_COLLATE="C" ls -l and see the same "issue".

This functionality is implemented using gnulib's filevercmp function, which has some caveats worth noting.

  • LC_COLLATE is ignored, which means ‘ls -v’ and ‘sort -V’ will sort non-numeric prefixes as if the LC_COLLATE locale category was set to ‘C’.

(via)

It means it will be sorted in ASCII order.

See also:

https://www.gnu.org/software/coreutils/manual/coreutils.html#Version-sort-ignores-locale


However, you could e.g. use python to sort your versions:

Install natsort module, e.g. if you have pip installed:

pip3 install natsort

Put the following in a python script (e.g. sortv.py):

#!/usr/bin/env python3
from natsort import humansorted
import sys
for line in humansorted(sys.stdin):
    print(line.rstrip())

Then run ls -1f | python /path/to/sortv.py.

This is nowhere perfect, it does not care about directories vs files, it should just show what you can do. Better would be to implement the whole thing in python and not pipe from ls which should never be parsed!

E.g.:

#!/usr/bin/env python3
import os
from natsort import humansorted
for (path, dirs, files) in os.walk('.'):
    for d in dirs:
        print('\033[94m{}\033[0m'.format(d))
    for f in humansorted(f):
        print(f)
    break
pLumo
  • 22,565
  • I tried LC_COLLATE=C ls -l, with and without -v and as you said, they do the same thing. So does this answer mean it can't be done without piping through sort or something else? – Jeff Feb 07 '22 at 14:33
  • This answer means it cannot be done with ls or sort. – pLumo Feb 07 '22 at 14:34
  • I'll give the python script a try in a bit. Thanks for taking the time and if you have anything else to add, it will be more than welcome. – Jeff Feb 07 '22 at 14:53
  • added a python-only ls -v. Need to be extended for more colors and ls -l functionality. It also does not take arguments but always uses current dir. – pLumo Feb 07 '22 at 14:59