Skip to content
01 - a GNU Core Utility - ls

01 - a GNU Core Utility - ls

Published: at 06:53 PM

Table of contents

Open Table of contents

Intro

I plan to make blog posts about GNU Core Utilities in more detail. ls will be the first one. Everyone knows how to use ls, but most are not familiar even with 90% of this command. So, this series will show basic commands’ lesser-known but useful functionalities.


ls is a command to list directory content. It was written by Richard M. Stallman and David MacKenzie.

Processed Documentation

Basic

You can skip if you’re already familiar with how ls works at the surface.

First of all:

Most commonly used options

# Get help
ls --help
man ls

# List current directory
ls
another_folder  some_file  some_folder

# List all files including hidden ones
ls -a
.  ..  another_folder  .seemefile  some_file  some_folder

# Long listing format with permissions, size, timestamp, etc.
ls -l
total 12
drwxr-xr-x 2 elnur users 4096 Jul 16 22:42 another_folder
-rw-r--r-- 1 elnur users   13 Jul 16 22:41 some_file
drwxr-xr-x 2 elnur users 4096 Jul 16 22:41 some_folder

# Combine options
ls -la
total 20
drwxr-xr-x  4 elnur users 4096 Jul 16 22:47 .
drwx------ 36 elnur users 4096 Jul 16 22:43 ..
drwxr-xr-x  2 elnur users 4096 Jul 16 22:42 another_folder
-rw-r--r--  1 elnur users    0 Jul 16 22:47 .seemefile
-rw-r--r--  1 elnur users   13 Jul 16 22:41 some_file
drwxr-xr-x  2 elnur users 4096 Jul 16 22:41 some_folder

Understanding the Long Listing Format (ls -l)

The long format reveals much more than just filenames. Here’s a breakdown of what this line means:

-rw-r-----  1 elnur users   13 Jul 16 22:41 some_file
FieldDescription
-rw-r--r--File permissions and type:
First character: file type (- = regular file)
Next 9 characters: permission bits in 3 groups: 
- First 3: Owner (user who owns the file) 
- Second 3: Group (users in the file’s group) 
- Last 3: Others (everyone else)
1Hard link count — Number of hard links to the file
elnurOwner — The user who owns the file
usersGroup — The group that owns the file
13File size in bytes
Jul 16 22:41Last modification date and time
some_fileFilename — The name of the file

If the file were a directory, symbolic link, or special file, the first character would change:

SymbolTypeNotes
-Regular fileStandard file
dDirectoryContains other files/directories
lSymbolic linkPoints to another file

In next 9 charachters, each group represents permissions:

SymbolMeaningApplies to
rreadCan read/view file contents
wwriteCan modify the file (or add/remove inside a directory)
xexecuteCan run the file if it’s a program or script (or cd into a directory)
-no permissionThat specific permission is not granted

Additional Information about -l will be covered later.

Intermediate

These options aren’t often used by beginners, but they’re useful in real-world scripting or file inspection tasks:

Show All Files (but skip . and ..)

ls -a shows hidden files and ., .. entries, which can clutter the output. So, you can do the following:

ls -A
another_folder  .seemefile  some_file  some_folder

Ignore Backup Files

Some editors create temporary or backup files ending in ~

ls
config.txt  config.txt~  notes.txt

ls -B # or ls --ignore='*~'
config.txt  notes.txt

Great for directories filled with auto-saved files you don’t care about.

Only List Directories Themselves

By default, if you give ls a directory name, it lists its contents. But if you want to output only directories:

ls -d */
another_folder/  some_folder/
# Or for a specific directory:
ls -d my_folder
my_folder

Ignore Specific File Patterns

Use --ignore or -I:

# ignore specific pattern
ls --ignore='*.log'
# or patterns
ls --ignore='*.log' --ignore='*.tmp'
# ---
ls
app.log  app.tmp  app.py

ls --ignore='*.log' --ignore='*.tmp'
app.py

By default, ls lists the symlink itself, not the file it points to. If you want details about the target file, you use -L or --dereference:

ls -lL my_link

This shows permissions, owner, and size of the destination file.

ls -l latest_report
lrwxrwxrwx 1 elnur users 10 Avq  2 16:38 latest_report -> report.txt
ls -lL latest_report
-rw-r--r-- 1 elnur users 17 Avq  2 16:38 latest_report

Useful for checking if a symlink is valid or broken.

ls -l broken_link
lrwxrwxrwx 1 elnur users 11 Avq  2 16:39 broken_link -> missing.txt
ls -lL broken_link
ls: cannot access 'broken_link': No such file or directory

Recursively List Everything

To see all files in all subdirectories, use -R or --recursive:

ls
another_folder	some_file  some_folder	some.json

ls -R
.:
another_folder	some_file  some_folder	some.json

./another_folder:
another_file.txt  baby_folder

./another_folder/baby_folder:

./some_folder:

Human-Readable File Sizes

By default, file sizes in ls -l are shown in bytes, which is hard to scan for large files.

ls -lh
total 16K
drwxr-xr-x 3 elnur users 4,0K Avq  2 16:45 another_folder
-rw-r--r-- 1 elnur users   13 İyl 16 22:41 some_file
drwxr-xr-x 2 elnur users 4,0K İyl 16 22:41 some_folder
-rw-r--r-- 1 elnur users 3,8K İyl 28 13:02 some.json

# K = kilobytes (1024 bytes)
# M = megabytes
# G = gigabytes

If you prefer SI units (powers of 1000, not 1024):

ls --si -l
total 17k
drwxr-xr-x 3 elnur users 4,1k Avq  2 16:45 another_folder
-rw-r--r-- 1 elnur users   13 İyl 16 22:41 some_file
drwxr-xr-x 2 elnur users 4,1k İyl 16 22:41 some_folder
-rw-r--r-- 1 elnur users 3,9k İyl 28 13:02 some.json

More File Types with -l

In the basic section, you saw common file types (- = file, d = directory, l = symlink). But ls -l can show other types too:

SymbolTypeNotes
bBlock deviceHardware devices that read/write data in blocks (e.g., disks)
cCharacter deviceHardware devices with stream-based access (e.g., keyboard, terminal)
pNamed pipe (FIFO)Special file for inter-process communication
sSocketNetwork or inter-process communication endpoint
DDoor (Solaris)Special file type for fast RPC calls on Solaris systems
MMigrated fileFile stored offline (e.g., on tape or remote storage)
ls -l /dev
brw-rw----  1 root disk    8,   0 Jul 16 22:41 sda
crw-rw-rw-  1 root root    1,   3 Jul 16 22:41 null
mkfifo pipppip
ls -l
prw-r--r-- 1 elnur users    0 Avq  2 17:09 pipppip

Advanced

Show Full Timestamps

By default, ls -l shows only month, day, and time (or year, if not modified recently).
--full-time reveals the complete timestamp with seconds and timezone:

ls --full-time
-rw-r--r-- 1 elnur users 13 2024-07-16 22:41:02.000000000 +0400 some_file

Group-Only or Owner-Only Listing

When you want to hide some columns in ls -l:

ls -l
-rw-r--r-- 1 elnur users 3887 İyl 28 13:02 some.json
ls -g
-rw-r--r-- 1 users 3887 İyl 28 13:02 some.json
ls -o
-rw-r--r-- 1 elnur 3887 İyl 28 13:02 some.json
ls -lG
-rw-r--r-- 1 elnur 3887 İyl 28 13:02 some.json

Show Inode Numbers

Every file has an inode in the filesystem.

ls -i
14156904 another_folder  11373995 some_file  14156903 some_folder  11374841 some.json

What is the application of such knowledge? - you would ask.

Knowing the inode of one file you can find its hard link in another place:

ls -i some.json
11374841 some.json
find . -inum 11374841
./remote_folder/another.json
./some.json

Delete Files with Annoying and Strange Names

Sometimes files have names that are hard to type (e.g., starting with -, containing spaces, or control characters). You can delete them by inode:

ls -i
14156904 another_folder  14171799 remote_folder  11373995 some_file  14156903 some_folder  11374841 some.json  11297265 у_тебя_нет_кириллицы_ха-ха-ха
find . -inum 11297265  -exec rm {} \;
ls
another_folder	remote_folder  some_file  some_folder  some.json

(Yes, some shells allow you to Tab-Tab or copy and paste, but some not)

Show Disk Usage in Blocks

With -s or --size, ls shows how many filesystem blocks a file occupies:

ls -s
total 20
4 another_folder  4 remote_folder  4 some_file	4 some_folder  4 some.json
ls -sh
total 20K
4,0K another_folder  4,0K remote_folder  4,0K some_file  4,0K some_folder  4,0K some.json

Units depend on the filesystem’s block size. Use -h with -s for human-readable sizes.

Show SELinux Context

If your system uses SELinux, -Z displays the security context:

ls -Z
-rw-r--r--. elnur users unconfined_u:object_r:user_home_t:s0 some_file

Handy for debugging permission issues in SELinux-enabled environments.

Sorting the Output

ls can sort by different criteria:

OptionSort byNotes
-tmodification time (newest)Combine with -r for oldest first
-ulast access timeWorks with -t or --sort=time
-Sfile size (largest first)Combine with -r for smallest first
-XextensionGroups files by suffix
ls
another_folder	remote_folder  some_file  some_folder  some.json
ls -t
remote_folder  another_folder  some.json  some_file  some_folder
ls -tr
some_folder  some_file	some.json  another_folder  remote_folder

ls
a.json	another_folder	a.txt  b.txt  remote_folder  some_file	some_folder  some.json
ls -X
another_folder	remote_folder  some_file  some_folder  a.json  some.json  a.txt  b.txt

You can also use the explicit --sort=WORD form:

--sort=size
--sort=extension
--sort=none

To disable sorting (faster for huge directories), use:

ls -f
# This also forces -a

General Output Formatting

You can also set environment variable LS_COLORS to control colors, or use --color=auto/always/never.

ls -1
another_folder
some_file
some_folder
some.json

ls -m
another_folder, some_file, some_folder, some.json

Formatting File Timestamps

Use --time=WORD to choose which time to display:

Combine with --time-style=STYLE to format the date:

ls --time-style=full-iso -l
total 16
drwxr-xr-x 3 elnur users 4096 2025-08-02 16:45:56.733863608 +0400 another_folder
-rw-r--r-- 1 elnur users   13 2025-07-16 22:41:41.544841538 +0400 some_file
drwxr-xr-x 2 elnur users 4096 2025-07-16 22:41:31.601828588 +0400 some_folder
-rw-r--r-- 1 elnur users 3887 2025-07-28 13:02:35.809927528 +0400 some.json

ls --time-style=+%Y/%m/%d_%H:%M -l
total 16
drwxr-xr-x 3 elnur users 4096 2025/08/02_16:45 another_folder
-rw-r--r-- 1 elnur users   13 2025/07/16_22:41 some_file
drwxr-xr-x 2 elnur users 4096 2025/07/16_22:41 some_folder
-rw-r--r-- 1 elnur users 3887 2025/07/28_13:02 some.json

Formatting the File Names

ls --quote-name
"another_folder"  "some_file"  "some_folder"  "some.json" "my file with spaces"

Practical Scenarios

You can find some use cases:

  1. Quickly Spot Large Files in a Directory Tree
ls -lhSR
  1. List Files Accessed in the Last 24 Hours
ls -ltu --time-style=full-iso | head
  1. Compare Two Files by Inode to Detect Hard Links
ls -i file1 file2
  1. Check Symlink Targets and Their Validity
ls -l
lrwxrwxrwx 1 elnur users 10 Aug  2 16:38 latest -> report.txt
ls -lL latest
-rw-r--r-- 1 elnur users 17 Aug  2 16:38 latest

If -lL fails with “No such file or directory,” the symlink is broken — time to fix it.

  1. See SELinux Context When Permissions Look Fine
ls -lZ

If a file has correct rw permissions but is still inaccessible, the SELinux label may be the reason. Compare with a working file to spot mismatches.

  1. Generate a Script-Friendly List of Files
ls -1Q --quoting-style=shell > files.txt

Perfect for feeding file lists into other scripts without worrying about spaces in names.

  1. List Only Directories, Sorted by Size
ls -lhd */ | sort -h -k5

Additional

eza: A Modern Replacement for ls

While ls is everywhere and dependable, many Linux users now prefer eza — a modern, colorful, and more feature-rich drop-in replacement.

eza keeps the core behavior of ls but adds:

eza

Honorable Mentions

Conclusion

ls might be one of the first commands you ever learn on Linux, but it’s far from basic.

Whether you’re a casual user cleaning up a folder, a sysadmin diagnosing a permissions issue, or a developer automating a deployment script, knowing these hidden gems will save you time and headaches.

References