Everyone knows ls, and almost everyone runs it on autopilot right past the flags that actually answer the question they have. This guide covers hidden entries, useful metadata, sort order, and the difference between a directory's own entry and its contents. Examples use GNU coreutils 9.4, package version 9.4-3ubuntu6.3. Ten minutes, plus whatever time a permissions problem costs you.
Everything here is read-only unless you redirect output to a file, and none of it needs elevated privileges. Swap in a real directory for /path/to/directory. Do not reach for sudo just because a listing failed; work out whether the path or its permissions are the actual problem first.
$ command -v ls
/usr/bin/ls
$ ls --version | head -1
ls (GNU coreutils) 9.4
Interactive shells often alias ls to something friendlier. That does not change which files exist, but it can inject terminal colour codes into anything you copy or redirect. Use command ls when you need output you can trust.
No path lists the current directory; a path lists that one instead. By default, names starting with a dot are hidden and the rest are sorted alphabetically:
$ ls /path/to/directory
archive
notes.txt
projects
Want directories visually marked? Add -p:
$ ls -p /path/to/directory
archive/
notes.txt
projects/
That trailing slash is a display indicator, nothing more; it renames nothing. In a script, check the object type with test -d instead of parsing punctuation.
Checkpoint: confirm the path itself is readable before layering on more options:
$ test -r /path/to/directory && echo "directory is readable"
directory is readable
-a or --all shows everything, including the special . and .. entries for the current and parent directory:
$ ls -la /path/to/directory
total 12
drwxr-xr-x 4 user user 4096 Sep 24 10:20 .
drwxr-xr-x 18 user user 4096 Sep 24 10:00 ..
drwxr-xr-x 2 user user 4096 Sep 24 10:18 .config
-rw-r--r-- 1 user user 0 Sep 24 10:20 notes.txt
./..? Use -A / --almost-all, easier to scan when hunting for config files.~ cluttering things up? -B hides them from the listing. It does not delete them.Watch the combination: -a overrides the hiding done by --ignore and --hide, so mixing filters does not do what you might expect.
-l gives one entry per line: type, permissions, link count, owner, group, size, modified time, name. Add -h for human-readable sizes:
$ ls -lh /path/to/directory
total 12K
drwxr-xr-x 4 user user 4.0K Sep 24 10:18 .config
-rw-r--r-- 1 user user 0 Sep 24 10:20 notes.txt
-rw-r--r-- 1 user user 11K Sep 23 16:04 report.txt
The first character tells you the type: d directory, - regular file, l symbolic link, and so on. The three permission triplets are owner, group, everyone else. A directory's size here is metadata for the directory itself, not a rolled-up total of everything inside it.
-h uses powers of 1024, so 4.0K is roughly 4096 bytes; use --si if you actually want powers of 1000. Neither totals a tree recursively.
For a symlink, plain ls -l describes the link itself. Add -L only when you want the target's information instead, never when the link is what you are auditing.
Passing a directory lists what is inside it by default. -d lists the directory entry itself, useful for checking a directory's own permissions without a second, unrelated listing tagging along:
$ ls -ld /path/to/directory
drwxr-xr-x 4 user user 4096 Sep 24 10:18 /path/to/directory
Same distinction matters everywhere: ls -ld /path/to/directory reports the directory, ls -l /path/to/directory reports its children. Quote paths with spaces:
$ ls -ld "/path/to/directory with spaces"
Sorting is a display choice, never a change to the directory. -t for newest first, -S for largest first, -r to reverse whichever you picked:
$ ls -lt /path/to/directory
$ ls -lSr /path/to/directory
The default timestamp is modification time. Add -u to ls -lt for access time instead, or -c for status-change time. These are genuinely different filesystem timestamps, and access time can get updated just by the act of inspecting it, or suppressed entirely by mount options.
-1 gives one name per line for feeding into another tool, or --zero for NUL-terminated lines. Do not treat plain ls output as machine-safe: names can contain whitespace and control characters. Use shell globs or a NUL-aware tool for that instead.
A missing path or unreadable subdirectory can exit 1, while a genuine command-line problem exits 2. Capture the status immediately if a script needs to tell them apart:
$ ls /path/to/maybe-missing
ls: cannot access '/path/to/maybe-missing': No such file or directory
$ printf 'ls exit status: %s\n' "$?"
ls exit status: 2
Check spelling, traversal permissions on the parent, and whether the path is a symlink before reaching for elevated access. Running ls as root can mask a real ownership problem, and can expose names you never meant to see. If you must inspect a protected directory as an administrator, confirm the exact path first and keep the command read-only.
Narrow the question instead of staring at a wall of output: -ld for one entry, -A for meaningful hidden files, -lt for recent changes, -lS for the big ones. Do not fire -R at a large tree casually, recursive output on a big filesystem is slow and enormous.
ls implementation and version.-d.-A, -l, -h, -t and -S.