ls is usually the very first command anyone learns in Bash, and it’s easy to assume you already know everything about it after typing it a few hundred times. But the truth is ls has a huge number of options that most people never touch, and once I started actually using flags like -lh, -t, and -R intentionally instead of just running bare ls every time, I realized how much time I’d been leaving on the table.
This guide covers everything from the basics of listing files to sorting, filtering, formatting output, and combining ls with other commands for more powerful directory inspection.
The Basic ls Command
ls
Run with no arguments, this lists the files and directories in your current working directory, typically sorted alphabetically.
Listing a Specific Directory
ls /home/user/documents
This lists the contents of the specified directory without needing to cd into it first.
Showing Hidden Files
Files and directories starting with a dot (.) are hidden by default, such as .bashrc or .gitignore.
ls -a
-a— shows all files, including hidden ones. Note this also includes.(current directory) and..(parent directory) in the output.
To show hidden files without those two special entries:
ls -A
-A— almost all, same as-abut excludes.and...
Long Listing Format
ls -l
-l— long format, showing detailed information for each file: permissions, number of links, owner, group, size, modification date, and filename.
A typical line looks like:
-rw-r--r-- 1 user user 4096 Jul 28 10:32 report.txt
Breaking this down:
-rw-r--r--— file type and permissions (a regular file, readable/writable by the owner, read-only for group and others).1— number of hard links.user user— owner and group.4096— file size in bytes.Jul 28 10:32— last modification date and time.report.txt— the filename.
Human-Readable File Sizes
ls -lh
-h— human-readable, converts raw byte counts into KB, MB, or GB, making file sizes far easier to read at a glance. This is almost always combined with-l.
Sorting Output
By Modification Time (Newest First)
ls -lt
-t— sort by modification time, most recently modified first.
By Modification Time (Oldest First)
ls -ltr
-r— reverse the sort order, so combined with-tthis shows oldest files first, which I find useful for quickly spotting the most recently changed file at the bottom of a scrolling terminal.
By File Size
ls -lS
-S— sort by file size, largest first.
Alphabetically Reversed
ls -r
Reverses whatever the default sort order is.
Recursive Listing
ls -R
-R— recursive, lists the contents of the specified directory and all of its subdirectories, showing the full nested structure.
This can produce a lot of output on large directory trees, so it’s often combined with head or piped through less for easier reading:
ls -R | less
Listing Only Directories
ls doesn’t have a dedicated flag for “directories only,” but you can achieve this with a glob pattern combined with the right options:
ls -d */
-d— list directory entries themselves rather than their contents.*/— a glob pattern that only matches directories (because of the trailing slash).
Showing File Type Indicators
ls -F
-F— appends a symbol to each entry indicating its type:/for directories,*for executables,@for symbolic links, and so on. This is a quick way to distinguish file types without needing the full-loutput.
Combining Common Flags
A combination I use constantly:
ls -lah
This shows a long listing (-l), including hidden files (-a), with human-readable sizes (-h) — a good all-purpose command for inspecting a directory thoroughly.
Colorized Output
Many distributions enable colorized ls output by default, distinguishing directories, executables, and symlinks visually. If it’s not enabled:
ls --color=auto
This is often set permanently via an alias in .bashrc:
alias ls='ls --color=auto'
Listing With Full Timestamps
By default, ls -l shows an abbreviated date format. For a full, unambiguous timestamp:
ls -l --time-style=full-iso
This is particularly useful in scripts or logs where date ambiguity (like whether “07/08” means July 8th or August 7th) could cause confusion.
One File Per Line
ls -1
-1— forces one entry per line, which is useful when pipinglsoutput into another command line by line, such as a loop.
Real-World Use Cases
Checking disk usage patterns: Using ls -lhS to quickly spot the largest files in a directory that might be worth cleaning up or archiving.
Auditing recent changes: Running ls -lt in a project directory after a deployment to confirm which files were actually updated.
Scripting file processing: Using ls -1 to generate a clean, one-per-line list of filenames to loop over in a Bash script.
Verifying permissions: Using ls -l to confirm that a script or binary has the executable bit set before trying to run it.
Combining ls With Other Commands
Counting Files in a Directory
ls -1 | wc -l
wc -l— counts the number of lines in the input, which here corresponds to the number of files listed one-per-line.
Finding the Most Recently Modified File
ls -t | head -n 1
This lists files sorted by modification time and grabs just the first (most recent) entry.
Listing Files Larger Than a Certain Size (Combined With awk)
ls -l | awk '$5 > 1000000 {print $9, $5}'
Here’s what’s happening:
ls -lproduces detailed output, where the 5th column is the file size in bytes and the 9th column is the filename.awk '$5 > 1000000 {print $9, $5}'filters for lines where the size exceeds 1,000,000 bytes and prints the filename alongside its size.
This is a simple but effective way to spot unusually large files without needing find.
Automation Example: Directory Snapshot Script
#!/bin/bash
TARGET_DIR="${1:-.}"
OUTPUT_FILE="directory_snapshot_$(date +%Y%m%d).txt"
echo "Snapshot of $TARGET_DIR taken on $(date)" > "$OUTPUT_FILE"
echo "----------------------------------------" >> "$OUTPUT_FILE"
ls -lahR "$TARGET_DIR" >> "$OUTPUT_FILE"
echo "Snapshot saved to $OUTPUT_FILE"
How this works internally:
TARGET_DIR="${1:-.}"— uses the first script argument as the target directory, defaulting to the current directory (.) if none is provided.OUTPUT_FILE="directory_snapshot_$(date +%Y%m%d).txt"— builds a filename that includes today’s date, so repeated runs don’t overwrite each other.- The
echolines write a simple header into the output file, including a timestamp for context. ls -lahR "$TARGET_DIR" >> "$OUTPUT_FILE"appends a full recursive, detailed, human-readable listing of the target directory to the snapshot file.- This kind of snapshot is genuinely useful before making significant changes to a directory (like a major refactor or migration), giving you a documented “before” state you can compare against later.
Best Practices
- Combine
-land-halmost every time you need file sizes — raw byte counts are hard to parse mentally. - Use
-asparingly and intentionally, since hidden configuration files can clutter output when you just want a quick overview. - Prefer
-1when pipinglsoutput into scripts, to guarantee one filename per line regardless of terminal width. - Set up a colorized
lsalias in.bashrcif your system doesn’t already have one, since color coding makes directories and executables far easier to distinguish at a glance. - For anything beyond simple listing (filtering by size, date range, or type), reach for
findinstead of trying to forcelsto do more than it’s designed for.
Security Considerations
- Avoid relying on parsing
ls -loutput in scripts for anything security-critical — filenames containing unusual characters (like newlines) can make column-based parsing unreliable. For robust scripting, preferfindwith-print0andread -d ''to handle filenames safely. - Be cautious listing directories you don’t own with
-l, since ownership and permission details are visible and could reveal information about system users or services you weren’t expecting to see.
Optimization Tips
- Avoid
-R(recursive) on very large directory trees when you only need part of the structure — combine with-dand glob patterns, or usefind -maxdepthinstead for more targeted results. - When scripting, avoid unnecessary
lscalls in loops; if you need file metadata repeatedly, consider capturing the listing once and processing it, rather than callinglsfresh each iteration.
Troubleshooting Common Issues
Hidden files not showing up: You forgot the -a or -A flag — remember ls hides dotfiles by default.
Colors not appearing in output: Your terminal or system might not have colorized ls enabled by default; try ls --color=auto explicitly or check your .bashrc for a conflicting alias.
Sorting by date looks wrong: Double check whether you wanted -t (newest first) or -tr (oldest first) — it’s easy to mix these up.
Parsing ls -l output in a script breaks on filenames with spaces: This is a sign you should switch to find with null-terminated output instead of trying to parse ls column by column.
Frequently Asked Questions
What’s the difference between -a and -A? -a shows all files including . and .., while -A shows hidden files but excludes those two special directory entries.
Can I list files sorted by size and see human-readable sizes at the same time? Yes: ls -lhS combines long format, human-readable sizes, and size-based sorting in one command.
Why does ls -l show a total line at the top for directories? That’s the total disk block usage of the listed files, not the sum of file sizes shown in bytes — it’s a leftover from older Unix conventions and can be safely ignored for most purposes.
Is it safe to parse ls output in scripts? Generally, no — for anything beyond casual visual inspection, prefer find, stat, or shell globbing directly, since ls output isn’t designed to be machine-parsed reliably.
Common Mistakes to Avoid
- Forgetting
-aand assuming a directory is empty when it actually contains only hidden files. - Confusing
-tand-Ssorting flags and getting unexpected ordering. - Parsing
ls -lcolumn output in scripts instead of using more robust tools likefindorstat. - Running
-Ron very large directories and getting overwhelmed with output instead of narrowing the scope first.
Summary
ls is deceptively simple on the surface but genuinely powerful once you start using its full set of flags intentionally. Learning to combine -l, -a, -h, -t, -S, and -R gives you fast, flexible control over how you inspect files and directories, whether you’re checking disk usage, auditing recent changes, or feeding filenames into a script. For anything requiring filtering by size, date range, or type beyond what ls sorting offers, pairing it with find rounds out a complete file inspection toolkit.
References
- GNU Coreutils Manual — ls: https://www.gnu.org/software/coreutils/manual/html_node/ls-invocation.html
- GNU Bash Manual: https://www.gnu.org/software/bash/manual/bash.html
