ls --group-directories-first
displays all directories before files, but if there is a symlink to a directory, it is displayed among the files. Is there a way to group directory-symlinks with other regular directories?
2 Answers
Consider using -L
. For example:
$ ls -l
total 4
-rw-r--r-- 1 ja users 0 Dec 20 13:23 A
drwxr-xr-x 2 ja users 4096 Dec 20 13:23 b
lrwxrwxrwx 1 ja users 1 Dec 20 13:23 sl -> b
$ ls --group-directories-first -l
total 4
drwxr-xr-x 2 ja users 4096 Dec 20 13:23 b
-rw-r--r-- 1 ja users 0 Dec 20 13:23 A
lrwxrwxrwx 1 ja users 1 Dec 20 13:23 sl -> b
$ ls --group-directories-first -lL
total 8
drwxr-xr-x 2 ja users 4096 Dec 20 13:23 b
drwxr-xr-x 2 ja users 4096 Dec 20 13:23 sl
-rw-r--r-- 1 ja users 0 Dec 20 13:23 A
I don't think that's possible without -L
(which gives you information on the target of the symlink instead of the symlink).
you could always run two
ls invocations, one for the directories, one for the non-directories. With zsh
:
lldirfirst() {
local -a dir nondir
local ret=0
dir=(*(N-/)) nondir=(*(N^-/))
(($#dir == 0)) || ls -ld -- $dir || ret=$?
(($#nondir == 0)) || ls -ld -- $nondir || ret=$?
return $ret
}
That's for ls -l
in the current directory only, it would need to be adapted to list other files/dirs.
Also beware column alignment may get broken:
$ lldirfirst
drwxr-xr-x 2 chazelas chazelas 4096 Dec 20 13:20 c
lrwxrwxrwx 1 chazelas chazelas 1 Dec 20 13:20 d -> c
-rw-r--r-- 1 chazelas chazelas 0 Dec 20 13:20 a
-rw-r--r-- 1 chazelas chazelas 0 Dec 20 13:20 b
Another option would be to use -qF
and sort the lines that end in /
first (assumes GNU ls
as not all ls
implementation will put a /
there for symlinks to directories, and a sort
implementation that supports -s
like GNU sort
, but your --group-directories-first
is GNU specific already anyway):
lsdirfirst() {
ls -qF "$@" |
awk '{if(/^total [0-9]+$/ || /\/$/) n=1; else n=2; print n, $0}' |
sort -sk1,1 | cut -d' ' -f2-
}
Example:
$ lsdirfirst -l
total 4
drwxr-xr-x 2 chazelas chazelas 4096 Dec 20 13:20 c/
lrwxrwxrwx 1 chazelas chazelas 1 Dec 20 13:20 d -> c/
-rw-r--r-- 1 chazelas chazelas 0 Dec 20 13:20 a
-rw-r--r-- 1 chazelas chazelas 0 Dec 20 13:20 b
Note that with zsh
, you can tell its completion system to list the directories first with:
zstyle ':completion:*' list-dirs-first true
And it does put symlinks to directories in the directory category:
$ ls Tab Completing directory c/ d@ Completing files a b
(with colors and those Completing... descriptions if enabled with more zstyle
s)
You can enable that completion style on a per-command basic by changing that zstyle
command to:
zstyle ':completion:*:*:(ls|echo):*:*' list-dirs-first true
for instance to enable it only for the ls
and echo
commands.
Here's an example of ~/.zshrc
configuration to get that output in color above.
eval "$(dircolors -b)"
zstyle ':completion:*' completer _expand _complete _ignored _correct _approximate _prefix
zstyle ':completion:*' format 'Completing %d'
zstyle ':completion:*' group-name ''
zstyle ':completion:*' menu select=2
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
zstyle ':completion:*' list-dirs-first true
autoload -Uz compinit
compinit -i
See also the compinstall
function for a menu-based interface to configure zsh completion.
-
IIUC,
mll
presented here unix.stackexchange.com/a/111639/72304 would do what OP wants inbash
, right? Dec 20, 2017 at 15:12 -
If anyone uses the
lsdirfirst()
function and wants to use the human-readable-h
option, modify the regex to read/^total [0-9\.]+\w+?$/
. Without this, the "total" will display between the directories and files, which is not where it should display. Dec 26, 2018 at 20:29
-L
do what you want?bash
.