ls lists directory contents. You’ll type it hundreds of times a day on a server. Learning a handful of options, and how to read the long format, gives you most of what you need to know about a file at a glance.
Basics
ls # current directory
ls /etc/nginx # another directory
ls *.conf # files matching a pattern
ls -d */ # only directories
Long format: ls -l
ls -l
-rw-r--r-- 1 deploy www-data 4523 Oct 14 09:12 index.php
drwxr-xr-x 3 deploy www-data 4096 Oct 10 18:40 uploads
lrwxrwxrwx 1 root root 34 Sep 2 11:05 current -> /srv/app/releases/20260902
From left to right:
- Type and permissions: the first character is the type (
-file,ddirectory,lsymlink,ssocket,b/cdevice). Then come three triplets for owner, group and others. See Linux file permissions. - Link count.
- Owner and group.
- Size in bytes. For directories this is the size of the directory entry, not its contents.
- Modification time.
- Name. Symlinks show their target after
->.
A + after the permissions (-rw-r--r--+) means ACLs are set. A . means an SELinux context.
The options you’ll actually use
ls -la # include hidden files (names starting with .)
ls -lA # hidden files, but without . and ..
ls -lh # human-readable sizes (K, M, G)
ls -lt # sort by modification time, newest first
ls -ltr # oldest first (newest at the bottom, handy in log directories)
ls -lS # sort by size, largest first
ls -lSr # smallest first
ls -R # recursive
ls -1 # one name per line (good for piping)
ls -i # show inode numbers
ls -n # numeric UID/GID instead of names
ls -F # add / to dirs, * to executables, @ to symlinks
Combine them freely. ls -lahtr gives all files, human-readable sizes, oldest first. It’s a favourite for checking which log or upload changed most recently.
Times: modification, access, change
ls -l shows modification time (mtime) by default. Other times:
ls -lu # access time
ls -lc # status change time (permissions, ownership)
ls -l --time-style=long-iso # 2026-10-14 09:12 — unambiguous
ls -l --time-style=full-iso # with seconds and timezone
For full details on one file, stat file shows all timestamps, the inode, permissions in octal and more.
Directory sizes
ls doesn’t show how much space a directory’s contents use. Use du:
du -sh /var/www/*
Colours and aliases
Most distributions alias ls to ls --color=auto. Common aliases to add to ~/.bashrc:
alias ll='ls -lAh'
alias lt='ls -lAhtr'
Run source ~/.bashrc to apply them. \ls runs ls without any alias.
Don’t parse ls in scripts
ls output is meant for humans. Filenames with spaces, newlines or odd characters break scripts like for f in $(ls). Use globs or find:
for f in /var/backups/*.sql.gz; do echo "$f"; done
find /var/backups -name '*.sql.gz' -mtime +7 -print
To count files, use find dir -maxdepth 1 -type f | wc -l rather than ls | wc -l.
Alternatives
treeshows a directory tree (apt install tree). Trytree -L 2 /srv/app.eza(formerly exa) is a modernlswith colours, git status and icons.statgives detailed metadata for one file.
Troubleshooting
ls: cannot open directory '.': Permission denied — you lack read permission on the directory. Use sudo ls, or check the directory’s permissions with ls -ld.
ls hangs — usually a stale network mount (NFS, SSHFS) in the path, or a directory with millions of files. With huge directories, ls -f (unsorted) returns much faster.
A file shows ????????? — you can read the directory but don’t have execute (x) permission on it, so ls can’t get each file’s details.
Quick reference
| Task | Command |
|---|---|
| Long listing, human sizes | ls -lh |
| Include hidden files | ls -la |
| Newest at bottom | ls -ltr |
| Largest first | ls -lS |
| Only directories | ls -d */ |
| Recursive | ls -R |
| ISO timestamps | ls -l --time-style=long-iso |