opscape

Files and directories

ls

List the contents of directories, or the details of individual files.

ls [OPTION...] [FILE...]

13 of 13 examples run in Debian 13.7 on 2026-10-31 · coreutils 9.7-3 · manual: ls(1)

ls lists the entries of a directory (the current one if you give no argument). Given a file instead of a directory, it lists just that file. By default it hides names that start with a dot and sorts alphabetically; nearly every option changes either what is shown (-a, -d, -R) or how it is sorted and formatted (-l, -t, -S, -h, -1).

When its output goes to a terminal, ls arranges names in columns. When it goes to a pipe or a file it prints one name per line instead, which is why ls | wc -l counts entries. That does not make ls output safe to parse: a filename can contain spaces or even newlines. In scripts, loop over a glob (for f in *.txt) or use find with -print0.

For the metadata of a single file in a fixed format, stat is the better tool; for a picture of a whole directory tree, tree.

Examples

List the current directory

ls
explain
output
README.md
access.log
data
file with spaces.txt
link-to-notes
logs
notes.txt
photos
scripts
src
todo.txt

Names are sorted alphabetically and dotfiles such as .env are hidden. Because the output here is not a terminal, ls prints one name per line; in an interactive shell you would see columns. Note that file with spaces.txt is a single entry, which is why parsing this text word by word goes wrong.

Show permissions, owner, size and date

ls -l
explain
output
total 6
-rw-rw-r-- 1 dev dev  230 Oct 24 02:38 README.md
-rw-rw-r-- 1 dev dev 2309 Oct 24 21:55 access.log
drwxrwxr-x 2 dev dev   13 Oct 25 01:33 data
-rw-rw-r-- 1 dev dev   34 Oct 24 09:47 file with spaces.txt
lrwxrwxrwx 1 dev dev    9 Oct 25 02:48 link-to-notes -> notes.txt
drwxrwxr-x 2 dev dev    5 Oct 25 17:10 logs
-rw-rw-r-- 1 dev dev  190 Oct 25 05:30 notes.txt
drwxrwxr-x 2 dev dev    5 Oct 25 13:50 photos
drwxrwxr-x 2 dev dev    4 Oct 25 21:27 scripts
drwxrwxr-x 3 dev dev    7 Oct 26 01:56 src
-rw-rw-r-- 1 dev dev   62 Oct 24 21:28 todo.txt

Each line is: file type and permission bits, link count, owner, group, size in bytes, modification time, and name. A leading d marks a directory, l a symlink (shown with -> target). total is the disk space used by the listed files, in 1 KiB blocks.

Include hidden files

ls -la
explain
output
total 15
drwxrwxr-x 7 dev dev   14 Oct 29 09:26 .
drwx------ 1 dev dev    7 Oct 31 20:20 ..
-rw-rw-r-- 1 dev dev   42 Oct 24 09:33 .env
-rw-rw-r-- 1 dev dev  230 Oct 24 02:38 README.md
-rw-rw-r-- 1 dev dev 2309 Oct 24 21:55 access.log
drwxrwxr-x 2 dev dev   13 Oct 25 01:33 data
-rw-rw-r-- 1 dev dev   34 Oct 24 09:47 file with spaces.txt
lrwxrwxrwx 1 dev dev    9 Oct 25 02:48 link-to-notes -> notes.txt
drwxrwxr-x 2 dev dev    5 Oct 25 17:10 logs
-rw-rw-r-- 1 dev dev  190 Oct 25 05:30 notes.txt
drwxrwxr-x 2 dev dev    5 Oct 25 13:50 photos
drwxrwxr-x 2 dev dev    4 Oct 25 21:27 scripts
drwxrwxr-x 3 dev dev    7 Oct 26 01:56 src
-rw-rw-r-- 1 dev dev   62 Oct 24 21:28 todo.txt

-a shows names starting with a dot, including . (this directory) and .. (its parent). -A is the same without those two, which is usually what you want in scripts.

Human-readable sizes

ls -lh data
explain
output
total 5.5K
-rw-rw-r-- 1 dev dev 244 Oct 25 21:53 config.json
-rw-rw-r-- 1 dev dev  66 Oct 25 17:04 fruits.txt
-rw-rw-r-- 1 dev dev  65 Oct 25 17:38 hosts.txt
-rw-rw-r-- 1 dev dev  59 Oct 26 08:21 inventory.tsv
-rw-rw-r-- 1 dev dev  27 Oct 26 09:05 numbers.txt
-rw-rw-r-- 1 dev dev  78 Oct 26 20:12 poem.txt
-rw-rw-r-- 1 dev dev 405 Oct 26 08:37 sales.csv
-rw-rw-r-- 1 dev dev 503 Oct 26 05:19 servers.json
-rw-rw-r-- 1 dev dev 149 Oct 26 17:44 settings.conf
-rw-rw-r-- 1 dev dev 436 Oct 27 08:26 users.csv
-rw-rw-r-- 1 dev dev  20 Oct 26 18:06 windows.txt

-h prints sizes with a unit suffix (K, M, G) once they reach 1024 bytes. Every file in data/ is under 1 KiB, so only the total line gets a suffix; on a directory of logs or images you would see 4.0K, 12M and so on.

Newest files first

ls -lt logs
explain
output
total 2
-rw-rw-r-- 1 dev dev 150 Oct 27 13:12 app.log.1
-rw-rw-r-- 1 dev dev 729 Oct 27 03:10 app.log
-rw-rw-r-- 1 dev dev 112 Oct 27 00:38 error.log

-t sorts by modification time, newest first. Add -r to reverse the order, so the most recently changed file ends up at the bottom, right above your prompt: ls -ltr.

Largest files first

ls -lS photos
explain
output
total 2
-rw-rw-r-- 1 dev dev 2315 Oct 28 05:43 forest.png
-rw-rw-r-- 1 dev dev 1587 Oct 27 18:41 beach.png
-rw-rw-r-- 1 dev dev  583 Oct 27 04:29 IMG_2041.png

-S sorts by size, largest first. Combine with -r to put the smallest first.

Show a directory itself, not its contents

ls -ld data src
explain
output
drwxrwxr-x 2 dev dev 13 Oct 25 01:33 data
drwxrwxr-x 3 dev dev  7 Oct 26 01:56 src

Without -d, ls -l data lists what is inside data. With -d you get one line for the directory itself, which is how you check its own permissions and owner.

Mark directories, executables and links

ls -F src
explain
output
Makefile
app.py*
lib/
main.c
util.sh*

-F appends a marker to each name: / for directories, * for executables (app.py and util.sh have the execute bit), and @ for symbolic links, as link-to-notes@ would show in the parent directory. It tells types apart without relying on color.

List subdirectories recursively

ls -R src
explain
output
src:
Makefile
app.py
lib
main.c
util.sh

src/lib:
helpers.py

-R lists the directory, then each subdirectory under its own path: heading. For anything bigger than a few levels, tree or find gives a more readable result.

List only files matching a pattern

ls -l data/*.csv
explain
output
-rw-rw-r-- 1 dev dev 405 Oct 26 08:37 data/sales.csv
-rw-rw-r-- 1 dev dev 436 Oct 27 08:26 data/users.csv

The shell expands data/*.csv before ls runs, so ls simply receives two file names and lists those. ls itself does not understand wildcards.

Full, sortable timestamps

ls -l --time-style=long-iso logs
explain
output
total 2
-rw-rw-r-- 1 dev dev 729 2026-10-27 03:10 app.log
-rw-rw-r-- 1 dev dev 150 2026-10-27 13:12 app.log.1
-rw-rw-r-- 1 dev dev 112 2026-10-27 00:38 error.log

The default date format drops the year for recent files and the time for old ones. --time-style=long-iso always prints YYYY-MM-DD HH:MM, and full-iso adds seconds, fractions and the time zone.

Count the entries in a directory

ls -A data | wc -l
explain
output
11

When ls writes to a pipe it puts one name per line (the same as -1), so wc -l counts entries. -A includes dotfiles but not . and ... Names with newlines would be counted twice, a rare but real reason to prefer find in scripts.

What happens when a file does not exist

ls notes.txt missing.txt
explain
outputexit 2
ls: cannot access 'missing.txt': No such file or directory
notes.txt

ls reports the missing name on standard error, still lists the ones that exist, and exits with status 2 ("serious trouble"); 1 is reserved for minor problems such as an unreadable subdirectory.

Common pitfalls

  • Parsing ls output (for f in $(ls)) breaks on spaces and newlines in names; file with spaces.txt would become three words. Use a glob: for f in *; do ...; done.

  • ls -l on a symlink to a directory shows the link; ls -l link/ (trailing slash) or ls -lL link shows what is inside or what it points at.

  • ls * with many files can fail with "Argument list too long": the shell expands the glob before ls runs. Use ls on the directory, or find.

  • Sizes in ls -l are apparent sizes. A sparse file can look huge while using almost no disk; du shows actual usage.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • Color: GNU uses ls --color=auto (often set as an alias); BSD/macOS uses ls -G or the CLICOLOR variable.

  • --time-style, --group-directories-first and other long options are GNU-only. macOS ls -lT shows the full time.

  • macOS ls -l may show an @ or + after the permissions for extended attributes or ACLs; GNU shows + for ACLs and . for an SELinux context.

Options worth knowing

A selection, described in our own words. For the full list, see ls(1) or ls --help.

OptionWhat it does
-lLong format: permissions, links, owner, group, size, time, name.
-a, --allInclude names starting with a dot, plus . and ..
-A, --almost-allInclude dotfiles but not . and ..
-h, --human-readableWith -l, print sizes like 4.0K and 12M.
-tSort by modification time, newest first.
-SSort by file size, largest first.
-r, --reverseReverse the sort order.
-R, --recursiveList subdirectories recursively.
-d, --directoryList directories themselves, not their contents.
-F, --classifyAppend / to directories, * to executables, @ to symlinks.
-1One name per line.
-i, --inodePrint each file's inode number.
-n, --numeric-uid-gidLike -l, but show numeric user and group IDs.
-L, --dereferenceShow the target of symlinks instead of the links.
-XSort alphabetically by extension.
-vNatural sort of numbers within names (file2 before file10).
-uWith -l, show access time; with -t, sort by it.
-cWith -l, show status-change time; with -t, sort by it.
--color[=WHEN]Colorize names: never, always or auto.
--time-style STYLEDate format: full-iso, long-iso, iso, locale or +FORMAT.
--group-directories-firstList directories before files.
--sort WORDSort by none, size, time, version, extension or width.

Related