I would like to use the ls
command to first show directories and then files. I tried:
ls -la | sort -k 1
But I got a wrong order.
Super User is a question and answer site for computer enthusiasts and power users. It only takes a minute to sign up.
Sign up to join this communityThe following command will list directories first, ordinary files second, and links third.
ls -la | grep "^d" && ls -la | grep "^-" && ls -la | grep "^l"
Also, it would make a great deal of sense to create an alias for this command to save keystrokes.
Edit:
If you want directories first, and then everything that is not a directory second, use this:
ls -la | grep "^d" && ls -la | grep -v "^d"
ls -la | grep "^d" && ls -la | grep "^-" && ls -la | grep -v -E "^d|^-|^total"
?
alias la="ls -la | grep \"^d\" && ls -la | grep \"^-\" && ls -la | grep -E \"^d|^-\" -v | grep -v \"^total\""
May 20, 2015 at 14:00
ls -la|grep ^d;ls -la|grep -v ^d
(quotes aren't required and replaced &&
with ;
). Another option is to introduce a variable and then evaluate it: a="ls -la|grep ^d";eval $a;eval $a -v
. Could be useful to avoid repetitions when much more options are specified to ls
/grep
. There's also that ls -la --group-directories-first
option, however the shortest imo is ls -la|sort
Mar 23, 2017 at 8:40
I do so love *nix and love seeing the inventiveness that goes into some of these replies...
Mine's not nearly as fancy on GNU Linux :
alias ls='ls --color -h --group-directories-first'
Given that I'm more comfortable with my linux CLI apps, I tend to also update coreutils on OSX :
brew install coreutils
alias ls='/usr/local/bin/gls --color -h --group-directories-first'
brew install bash
Then, this will work! :)
Jan 30, 2015 at 3:14
For the mac users, you can install coreutils.
This formula provides the GNU core utilities implementations, and for the commands that are also provided by macOS, they have been installed with the "g" prefix.
brew install coreutils
gls --color -h --group-directories-first
You can further simplify your life with an alias
alias ls='gls --color -h --group-directories-first'
PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
.
There are certain things I want to see in a directory listing, and so far none of the answers here meets all of the requirements below. My requirements for a directory listing:
./
and ../
), files, and links--group-directories-first
don't work in Git Bash for WindowsAfter much hacking about, I finally came up with a one-liner (albeit a very long line ;-)) that I'm satisfied with. I have assigned this to an alias named 'dir':
ls -dlF --color * .* | head -n2 && ls -AlF | LC_ALL=C grep "^d" |
LC_ALL=C sort -k 9df && ls -AlF | LC_ALL=C grep "^[l-]" |
LC_ALL=C sort -k 9df && echo -e `find -maxdepth 1 -type d ! -name . |
wc -l` Dir\(s\) `du -hs | cut -f 1`\\t\\t`find -maxdepth 1 -type f |
wc -l` File\(s\) `find -maxdepth 1 -type f -print0 | du -ch --files0-from=- |
tail -n 1 | cut -f 1`\\t\\t`find -maxdepth 1 -type l | wc -l` Link\(s\)
To make things easier to manage, I came up with separate commands to output each segment of the directory listing to my liking, then assembled them together using the &&
operator.
ls -dlF --color * .* | head -n2
-- Extract ./
and ../
. We don't want to pass these through sort
because they are already in the correct order, and sorting them can result in ../
being listed first. The -d
option is to get rid of the "total" line; I like to add -F
to show the trailing slash for directories (it will also mark symlinks with "@" when you do a plain ls -F
).
ls -AlF | LC_ALL=C grep "^d" | LC_ALL=C sort -k 9df
-- Extract the directories and sort them by filename (9th column), ignoring both non-alpha/space characters (d
option) and character case (f
option). The ls -A
option excludes ./
and ../
from the listing since we already extracted them in the previous step. I tend to prefix all grep
and sort
commands with the LC_ALL=C
locale reset so that (1) the output is consistent across Unix shells, and (2) you can sometimes see faster performance since it no longer has the overhead of the heavy UTF-8 character set to deal with.
ls -AlF | LC_ALL=C grep "^[l-]" | LC_ALL=C sort -k 9df
-- This is similar to the step above, but this time we are sorting files and symlinks.
find -maxdepth 1 -type d ! -name . | wc -l
-- Get the number of directories, excluding ./
and ../
.
find -maxdepth 1 -type f | wc -l
-- Get the number of files.
find -maxdepth 1 -type l | wc -l
-- Get the number of symlinks.
du -hs | cut -f 1
-- Extract the total size of all subdirectories in human-readable format.
find -maxdepth 1 -type f -print0 | du -ch --files0-from=- | tail -n 1 | cut -f 1
-- Extract the total size of all files in human-readable format.
Let's see our new dir
alias in action!
BEFORE:
$ ls -alF
total 22
drwxr-xr-x 13 Tom Administ 4096 Oct 25 02:38 ./
drwxr-xr-x 3 Tom Administ 0 Dec 24 2014 ../
drwxr-xr-x 15 Tom Administ 4096 Sep 17 01:23 .VirtualBox/
-rw-r--r-- 1 Tom Administ 615 Oct 25 02:38 .aliases
-rw-r--r-- 1 Tom Administ 12742 Oct 24 11:47 .bash_history
-rw-r--r-- 1 Tom Administ 3234 Oct 24 15:06 .bash_profile
drwxr-xr-x 1 Tom Administ 0 Jan 24 2015 .gem/
-rw-r--r-- 1 Tom Administ 586 Oct 24 03:53 .gitconfig
drwxr-xr-x 1 Tom Administ 4096 Dec 28 2014 .ssh/
drwxr-xr-x 4 Tom Administ 0 Jan 24 2015 .travis/
-rw-r--r-- 1 Tom Administ 6645 Oct 25 02:38 _viminfo
-rw-r--r-- 1 Tom Administ 4907 Oct 24 15:16 profile
drwxr-xr-x 1 Tom Administ 0 Oct 24 22:20 tmp/
AFTER:
$ dir
drwxr-xr-x 13 Tom Administ 4096 Oct 25 02:38 ./
drwxr-xr-x 3 Tom Administ 0 Dec 24 2014 ../
drwxr-xr-x 1 Tom Administ 0 Jan 24 2015 .gem/
drwxr-xr-x 1 Tom Administ 4096 Dec 28 2014 .ssh/
drwxr-xr-x 1 Tom Administ 0 Oct 24 22:20 tmp/
drwxr-xr-x 4 Tom Administ 0 Jan 24 2015 .travis/
drwxr-xr-x 15 Tom Administ 4096 Sep 17 01:23 .VirtualBox/
-rw-r--r-- 1 Tom Administ 615 Oct 25 02:38 .aliases
-rw-r--r-- 1 Tom Administ 12742 Oct 24 11:47 .bash_history
-rw-r--r-- 1 Tom Administ 3234 Oct 24 15:06 .bash_profile
-rw-r--r-- 1 Tom Administ 586 Oct 24 03:53 .gitconfig
-rw-r--r-- 1 Tom Administ 4907 Oct 24 15:16 profile
-rw-r--r-- 1 Tom Administ 6645 Oct 25 02:38 _viminfo
5 Dir(s) 2.8M 6 File(s) 31K 0 Link(s)
One minor downside is that you cannot have colored listings, since the color control characters surrounding the filenames make the sorting too unreliable.
UPDATE
The alias above was painfully slow when executed from the root directory of a deep file system, so I have updated to this simpler but much more performant command:
ls -AFoqv --color --group-directories-first | tail -n +2 && find -maxdepth 1 -type f -printf '%s\n' | awk '{total+=$1} END {print total" bytes"}'
Sample output:
$ dir
drwxr-xr-x 1 Tom 0 Mar 29 13:49 .aws/
drwxr-xr-x 1 Tom 0 Mar 29 13:49 .gem/
drwxr-xr-x 1 Tom 0 Mar 29 19:32 .ssh/
drwxr-xr-x 1 Tom 0 Mar 29 13:49 .zbstudio/
drwxr-xr-x 1 Tom 0 Jun 16 2016 temp/
drwxr-xr-x 1 Tom 0 Jul 13 2016 vimfiles/
-rw-r--r-- 2 Tom 365 Mar 30 10:37 .aliases
-rw-r--r-- 1 Tom 16028 Mar 30 12:12 .bash_history
-rw-r--r-- 2 Tom 2807 Mar 30 12:12 .bash_profile
-rw-r--r-- 2 Tom 2177 Mar 29 23:24 .functions
-rw-r--r-- 1 Tom 1091 Mar 30 10:34 .gitconfig
-rw-r--r-- 1 Tom 8907 Mar 29 14:45 _viminfo
-rw-r--r-- 1 Tom 2444 Jul 13 2016 _vimrc
33819 bytes
Since the new version of Git Bash for Windows supports --group-directories-first
, we no longer have to fall back on sort
. Even though the new alias doesn't display as much information as the previous alias, the performance gains are more than worth it. As a perk, you also get colors!
You've got several choices, depending if you want to keep alphabetical order.
You could simply try :
ls -al | sort -k1 -r
or this, to keep alphabetic order for files with the same permissions :
ls -al | sort -k1,1 -k9,9 -r
or, as eleven81 said (but this version lists everything) :
ls -la | grep "^d" && ls -la | grep "^-" && ls -al | grep -v "^[d|-]"
ls- al|sort -k1 -r
works. What was missing is just the -r
flag.
./
and ../
won't be the first two lines, in that order. Other than that, I agree that it's the more efficient solution.
To delerious010's answer, I would add that if you want old-style ordering:
LANG=C ls -la --group-directories-first
(or use LC_ALL or LANGUAGE or LC_COLLATE set to "C").
This will give something similar to:
.
..
DIR
Dir
dir
.hidden
123
UC_FILE
Uc_file
lc_file
Although, if I recall correctly, the hidden dot files originally appeared before the directories.
ls -laX
will show you directories first in alphabetical order, but will screw the file list.
Long options:
ls
-l # List
--all
-X # Sort alphabetically by entry extension
Here's a function to do this (bash or zsh): And... I'm not suggesting this is the best way, but it's the one I came up with and am using right now:
function lss { # Shows directory listing with directories at the top. command ls --color=always $@ | egrep '^d|total' command ls --color=always $@ | egrep -v '^d|total'; }
ls -l
) in order to filter by file type like that. Also, this command will break on spaces (in bash). You need to quote like so: "$@"
If you want to use this approach, you could do something like so: function lss {local temp="$(command ls -l --color=always "$@")"; egrep --color=never '^d|total' <<<"$temp"; egrep --color=never -v '^d|total' <<<"$temp"}
Another way ...
find . -d 1 -type d | ls -la | sort -r
OR
ls -la | sort -r
OR
d=`find . -type d -d 1`;f=`find . -type f -d 1`; echo -e -DIRS- "\n$d\n" -FILES- "\n$f"
alias ls='ls -lhF --color'
list_sorted() {
ls $* | grep "^d";
ls $* | grep "^-";
ls $* | grep -v -E "^d|^-|^total"
}
alias ll=list_sorted
I use a combination of the solutions provided in the answers and comments here.
ls
First of all, I overwrite the default behavior for ls
:
-l
: Always display the list as a one-dimensional, vertical list-h
: Display file sizes in a human-readable fashion (e.g. 4.0K instead of 4096)-F
: Display indicators like a trailing slash for directoriesalias ls='ls -lhF --color'
ll
Next, I write a function containing the sorting logic. For each ls
I pass any originally passed arguments to it. That enables me using the alias from a different working directory than the one I want to list (i.e. ls -a ~
).
Also, each call to ls
is piped to a grep
command. Here, the sorting happens. ls -l | grep "^d"
for example only lists directories. If directories should be listed first, this needs to come first in the function as well. Next thing is files.
Lastly, I show everything that is neither a directory nor a file (nor the line showing total size of the directory contents). This is done by grepping directoy, regular file entries and the total entry and then inverting the result via the -v
argument.
list_sorted() {
# List directories
ls $* | grep "^d";
# List regular files
ls $* | grep "^-";
# List everything else (e.g. symbolic links)
ls $* | grep -v -E "^d|^-|^total"
}
Finally, I alias the function to a new command. In particular I don’t want to overwrite ls
in case my function breaking in some scenarios. Then I want to be able to use ls
. Alternatively, you can always invoke the un-aliased ls
command by invoking \ls
.
alias ll=list_sorted
;
instead of &&
as a delimiter for the commands. Otherwise, one is unable to list contents of directories not containing directories (the first ls command evaluates to false, thus not allowing the execution of the next command since it’s coupled with &&
. ;
avoids that.)This is a script solution. Lists just the names, no inode data, alphabetical, not case sensitive, formatted into columns. Although it's row-major instead of column major like the default output of ls. The columns get a little messy if there is a file name with >26 characters.
rm -f /tmp/lsout
ls -1p | grep / | sort -f >> /tmp/lsout
ls -1p | grep -v / | sort -f >> /tmp/lsout
IFS=$'\n' read -d '' -r -a lines < /tmp/lsout
printf "%-24s %-24s %-24s\n" "${lines[@]}"
And another, with some extra formatting.
rm -f /tmp/lsout
echo " ---- Directories ---- " >> /tmp/lsout
ls -1p | grep / | sort -f >> /tmp/lsout
IFS=$'\n' read -d '' -r -a lines < /tmp/lsout
printf "%-24s %-24s %-24s\n" "${lines[@]}"
rm -f /tmp/lsout
echo " ------- Files ------- " >> /tmp/lsout
ls -1p | grep -v / | sort -f >> /tmp/lsout
IFS=$'\n' read -d '' -r -a lines < /tmp/lsout
printf "%-24s %-24s %-24s\n" "${lines[@]}"
Output for the last one looks like the following, minus the colors:
---- Directories ---- archive/ bookmarks/
Desktop/ Documents/ Downloads/
fff/ health/ Library/
Movies/ Music/ Pictures/
Public/ rrf/ scifi/
testdir/ testdir2/
------- Files ------- @todo comedy
delme lll maxims
schedule vtokens style
Just remember not to alias or change the default behavior of ls since this script calls it.
Solve for each part separately, then combine at the end. Consider choosing this answer bc solving for each sub command helps you understand each part of the process, making you a better developer, this is in line with the unix/nix philosophy:
ls -lp | grep "/"
ls -lap | grep "/"
ls -lp | grep -v "/"
ls -lap | grep -v "/"
ls -lp | grep "/" && ls -lap | grep -v "/"
ls -lap | grep "/" && ls -lap | grep -v "/"
alias foldersThenFiles='ls -lap | grep "/" && ls -lap | grep -v "/"'
-
comes befored
when usingsort
ls -lh --group-directories-first