# 01 - a GNU Core Utility - ls

> Master the Linux ls command with this complete guide covering basic to advanced options, hidden features, and modern alternatives to boost your terminal productivity.

Author: Elnur Badalov
Published: 2025-08-09
Updated: 2025-08-09
Tags: linux, gnu
Source: https://elnurbda.com/posts/44-gnu-ls/
License: CC BY 4.0, please cite the source URL.

---

# 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:

- **Hidden files** are those that start with a dot (`.`)
- **Syntax:** `ls [OPTIONS]... [FILES]...`
  - Options can be multiple and combined like `-la`
  - If no file or directory is provided, it defaults to the current directory
- Exit codes:
  - `0`: success
  - `1`: minor issue (e.g., permission denied)
  - `2`: serious problem (e.g., file doesn’t exist)

### Most commonly used options

```bash
# 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:

```bash
-rw-r-----  1 elnur users   13 Jul 16 22:41 some_file
```

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

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

| Symbol | Type              | Notes                            |
| ------ | ----------------- | -------------------------------- |
| `-`    | **Regular file**  | Standard file                    |
| `d`    | **Directory**     | Contains other files/directories |
| `l`    | **Symbolic link** | Points to another file           |

In next 9 charachters, each group represents **permissions**:

| Symbol | Meaning           | Applies to                                                              |
| ------ | ----------------- | ----------------------------------------------------------------------- |
| `r`    | **read**          | Can read/view file contents                                             |
| `w`    | **write**         | Can modify the file (or add/remove inside a directory)                  |
| `x`    | **execute**       | Can run the file if it’s a program or script (or `cd` into a directory) |
| `-`    | **no permission** | That 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:

```bash
ls -A
another_folder  .seemefile  some_file  some_folder
```

### Ignore Backup Files

Some editors create temporary or backup files ending in `~`

```bash
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:

```bash
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`:

```bash
# 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
```

### Follow Symbolic Links (or Not)

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`:

```bash
ls -lL my_link
```

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

```bash
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.

```bash
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`:

```bash
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.

```bash
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):

```bash
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:

| Symbol | Type                  | Notes                                                                |
| ------ | --------------------- | -------------------------------------------------------------------- |
| `b`    | **Block device**      | Hardware devices that read/write data in blocks (e.g., disks)        |
| `c`    | **Character device**  | Hardware devices with stream-based access (e.g., keyboard, terminal) |
| `p`    | **Named pipe (FIFO)** | Special file for inter-process communication                         |
| `s`    | **Socket**            | Network or inter-process communication endpoint                      |
| `D`    | **Door (Solaris)**    | Special file type for fast RPC calls on Solaris systems              |
| `M`    | **Migrated file**     | File stored offline (e.g., on tape or remote storage)                |

```bash
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
```

```bash
mkfifo pipppip
ls -l
prw-r--r-- 1 elnur users    0 Avq  2 17:09 pipppip
```

For more information on named pipes and their practical applications, see my guide on [Named Pipes](/posts/12-named-pipe/).

## 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:

```bash
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`:

- `-g` → like `-l` but **omit owner** column.
- `-o` → like `-l` but **omit group** column.
- `-G` → or `--no-group` - **omit group** column and use `-l` with it

```bash
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](https://en.wikipedia.org/wiki/Inode) in the filesystem.

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

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

#### Find Hard Links

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

```bash
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:

```bash
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:

```bash
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**:

```bash
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:

| Option | Sort by                    | Notes                                |
| ------ | -------------------------- | ------------------------------------ |
| `-t`   | modification time (newest) | Combine with `-r` for oldest first   |
| `-u`   | last access time           | Works with `-t` or `--sort=time`     |
| `-S`   | file size (largest first)  | Combine with `-r` for smallest first |
| `-X`   | extension                  | Groups files by suffix               |

```bash
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:

```bash
--sort=size
--sort=extension
--sort=none
```

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

```bash
ls -f
# This also forces -a
```

### General Output Formatting

- `-1` → one entry per line (good for scripts)
- `-C` → multi-column output (default when output is a terminal)
- `-m` → comma-separated list
- `--format=long` / `--format=commas` → same effect as above, but explicit.

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

```bash
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:

- `--time=atime` / `access`
- `--time=ctime` / `status`
- `--time=mtime` / `modify` (default)

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

```bash
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

- **Quoting**: `--quote-name` wraps names in double quotes.
- **Literal**: `-N` or `--literal` shows raw names without escaping.
- **Escape**: `-b` shows non-printable characters as C-style escapes.
- **Octal**: `-q` hides unprintables as `?`.
- **Custom quoting**: `2WORD` (`literal`, `shell`, `c`, `escape`, etc.).

```bash
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

```bash
ls -lhSR
```

2. List Files Accessed in the Last 24 Hours

```bash
ls -ltu --time-style=full-iso | head
```

3. Compare Two Files by Inode to Detect Hard Links

```bash
ls -i file1 file2
```

4. Check Symlink Targets and Their Validity

```bash
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.

5. See SELinux Context When Permissions Look Fine

```bash
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.

6. Generate a Script-Friendly List of Files

```bash
ls -1Q --quoting-style=shell > files.txt
```

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

7. List Only Directories, Sorted by Size

```bash
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:

- **Git integration** — shows file Git status right in the listing
- **Icons** (with a nerd font)
- **Better colors and formatting**
- **Tree view** with `--tree`
- **More human-friendly output** by default

![eza](/assets/44-gnu-ls/eza.png)

- https://eza.rocks/

## Honorable Mentions

- `lsd`
- `tree`
- `colorls`

# 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

- https://www.man7.org/linux/man-pages/man1/ls.1.html
- https://www.gnu.org/software/coreutils/manual/html_node/ls-invocation.html