Linux CLI 37 ๐ง stat command and inodes
stat file.txt
stat -f ~/CLI/
stat reveals the metadata behind a file โ the information the filesystem keeps about it, separate from its contents. And behind every file on a Linux filesystem sits an inode: the data structure that actually holds that metadata. Understanding both is essential for anyone who wants to know what’s really going on with their files.
Key point: A filename is just a label. The inode is the real object. The directory entry maps a name to an inode number, and the inode holds everything else โ permissions, ownership, timestamps, size, and pointers to the data blocks.
a – stat command
stat displays information about a file or directory. The information includes metadata like size, permissions, timestamps, and more. It’s like ls -l but with far more detail.
| Field | Meaning |
|---|---|
| Size | Size in bytes |
| Blocks | Total blocks allocated on the HDD |
| IO Block | Size of each block in bytes |
| Device | Device ID in hexadecimal format |
| Inode | Inode number of the file |
| Links | Number of hard links |
| Access | File permissions (in symbolic form) |
| Uid | Owner ID (user) |
| Gid | Group ID |
| Access time | Last time the file was read |
| Modify time | Last time the file’s contents changed |
| Change time | Last time the file’s metadata changed |
| Birth time | When the file was created (if supported) |
Examples:
# Show information for a file
$ stat file.txt
File: file.txt
Size: 1024 Blocks: 8 IO Block: 4096 regular file
Device: 803h/2051d Inode: 1234567 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ kronos) Gid: ( 1000/ kronos)
Access: 2024-01-15 10:30:00.123456789 +0000
Modify: 2024-01-15 10:25:00.987654321 +0000
Change: 2024-01-15 10:25:00.987654321 +0000
Birth: 2024-01-10 08:00:00.000000000 +0000
# Show information for a directory
$ stat -f ~/CLI/
File: "/home/kronos/CLI/"
ID: 1234567890abcdef Namelen: 255 Type: ext2/ext3
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 26214400 Free: 20000000 Available: 19000000
Inodes: Total: 6553600 Free: 6000000
Reading the output:
| Line | What it tells you |
|---|---|
File: | The path |
Size: | File size in bytes |
Blocks: | 512-byte blocks allocated |
IO Block: | Preferred block size for I/O |
regular file | File type (regular, directory, symlink, etc.) |
Device: | Device number (hex/decimal) |
Inode: | The file’s inode number |
Links: | Hard link count |
Access: | Permission bits |
Uid: / Gid: | Owner and group |
Access: (time) | Last read |
Modify: | Last content change |
Change: | Last metadata change |
Birth: | Creation time |
Useful options:
| Option | Purpose |
|---|---|
-f | Show filesystem info instead of file info |
-c FORMAT | Custom output format |
-t | Terse output (one line) |
-L | Follow symlinks |
Custom formats with -c:
# Just the size
$ stat -c %s file.txt
1024
# Just the inode number
$ stat -c %i file.txt
1234567
# Just the permissions (octal)
$ stat -c %a file.txt
644
# Just the owner name
$ stat -c %U file.txt
kronos
# Terse, one-line output
$ stat -t file.txt
file.txt 1024 8 81a4 1000 1000 803 1234567 1 0 0 1705314600 1705314300 1705314300 1704806400
# Multiple fields in a custom format
$ stat -c 'File: %n | Size: %s bytes | Owner: %U | Inode: %i' file.txt
File: file.txt | Size: 1024 bytes | Owner: kronos | Inode: 1234567
Common format specifiers:
| Specifier | Meaning |
|---|---|
%n | File name |
%s | Size in bytes |
%b | Blocks allocated |
%i | Inode number |
%h | Hard link count |
%a | Permissions (octal) |
%A | Permissions (human) |
%u | User ID |
%U | User name |
%g | Group ID |
%G | Group name |
%x | Access time |
%y | Modify time |
%z | Change time |
%w | Birth time |
%F | File type |
b – inodes
Inodes are unique identifiers for files and directories. They represent the smallest unit of storage and are stored as blocks. Every file and directory on a Linux filesystem has exactly one inode.
What an inode contains:
- Permissions
- Owner (UID) and group (GID)
- Timestamps (access, modify, change, birth)
- Size
- Hard link count
- Pointers to data blocks
- File type
What an inode does NOT contain:
- The filename โ that lives in the directory entry
- The file contents โ those live in data blocks the inode points to
Key properties of inodes:
- Assigned a unique number when a file is created
- Remains the same through the file’s lifetime
- Used to track files and directories on a disk
- Each filesystem has a fixed number of inodes (set at creation)
- If you run out of inodes, you can’t create new files โ even with free space
Show a file’s inode number:
$ stat -c %i file.txt
1234567
Examples:
# Get the inode number
$ stat -c %i file.txt
1234567
# Same info with ls
$ ls -i file.txt
1234567 file.txt
# Compare inodes of two files
$ stat -c %i file1.txt file2.txt
1234567
1234568
# Different inodes โ different files
# Hard links share an inode
$ ln file.txt hardlink.txt
$ stat -c '%i %h %n' file.txt hardlink.txt
1234567 2 file.txt
1234567 2 hardlink.txt
# Same inode, link count = 2
# A symlink has its own inode, pointing to another
$ ln -s file.txt symlink.txt
$ stat -c '%i %F %n' file.txt symlink.txt
1234567 regular file file.txt
1234999 symbolic link symlink.txt
# Different inodes; symlink is its own file
# List inode usage on a filesystem
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda2 6553600 456789 6096811 7% /
tmpfs 408123 1234 406889 1% /run
/dev/sdb1 61054976 123456 60931520 1% /home
# Find files with a specific inode
$ find / -inum 1234567 2>/dev/null
/home/kronos/file.txt
# Delete a file by inode (useful for weird filenames)
$ find . -inum 1234567 -delete
# Show all inodes in a directory
$ ls -i
1234567 file.txt
1234568 notes.txt
1234569 todo.txt
How inodes and filenames relate:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Directory Entry โ
โ โ
โ "file.txt" โโโโโโโบ inode 1234567 โ
โ โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Inode 1234567 โ
โ โ
โ Permissions: 0644 โ
โ Owner: 1000 (kronos) โ
โ Group: 1000 (kronos) โ
โ Size: 1024 โ
โ Links: 1 โ
โ Access: 2024-01-15 10:30 โ
โ Modify: 2024-01-15 10:25 โ
โ Change: 2024-01-15 10:25 โ
โ Blocks: โโโโโโโบ data block 1 โ
โ โโโโโโโบ data block 2 โ
โ โโโโโโโบ data block 3 โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Why inodes matter:
- Hard links work because two names point to the same inode
- Deleting a file just removes the directory entry and decrements the inode’s link count; the data is freed when the count hits 0
- Moving within the same filesystem doesn’t change the inode โ it’s just a rename
- Running out of inodes stops file creation even if you have free disk space
ls -iandstatlet you inspect inode numbers directly
Complete Example Session
# ============================================
# PART 1: BASIC STAT
# ============================================
$ stat file.txt
File: file.txt
Size: 1024 Blocks: 8 IO Block: 4096 regular file
Device: 803h/2051d Inode: 1234567 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ kronos) Gid: ( 1000/ kronos)
Access: 2024-01-15 10:30:00.123456789 +0000
Modify: 2024-01-15 10:25:00.987654321 +0000
Change: 2024-01-15 10:25:00.987654321 +0000
Birth: 2024-01-10 08:00:00.000000000 +0000
# ============================================
# PART 2: STAT ON A DIRECTORY / FILESYSTEM
# ============================================
$ stat -f ~/CLI/
File: "/home/kronos/CLI/"
ID: 1234567890abcdef Namelen: 255 Type: ext2/ext3
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 26214400 Free: 20000000 Available: 19000000
Inodes: Total: 6553600 Free: 6000000
# ============================================
# PART 3: CUSTOM FORMATS
# ============================================
$ stat -c %s file.txt
1024
$ stat -c %i file.txt
1234567
$ stat -c %a file.txt
644
$ stat -c %U file.txt
kronos
$ stat -t file.txt
file.txt 1024 8 81a4 1000 1000 803 1234567 1 0 0 1705314600 1705314300 1705314300 1704806400
# ============================================
# PART 4: INODES AND HARD LINKS
# ============================================
# Create a hard link
$ ln file.txt hardlink.txt
$ stat -c '%i %h %n' file.txt hardlink.txt
1234567 2 file.txt
1234567 2 hardlink.txt
# Both point to the same inode, link count = 2
# Create a symlink
$ ln -s file.txt symlink.txt
$ stat -c '%i %F %n' file.txt symlink.txt
1234567 regular file file.txt
1234999 symbolic link symlink.txt
# Different inodes
# ============================================
# PART 5: INODE USAGE
# ============================================
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda2 6553600 456789 6096811 7% /
tmpfs 408123 1234 406889 1% /run
/dev/sdb1 61054976 123456 60931520 1% /home
# Find a file by inode
$ find / -inum 1234567 2>/dev/null
/home/kronos/file.txt
# Delete by inode
$ find . -inum 1234567 -delete
# ============================================
# PART 6: COMPARE INODES
# ============================================
# Two different files โ different inodes
$ stat -c %i a.txt b.txt
1234567
1234568
# Same file via different paths โ same inode
$ stat -c %i /home/kronos/file.txt ~/file.txt
1234567
1234567
# Same file via symlink โ different inode
$ stat -c %i file.txt symlink.txt
1234567
1234999
Quick Reference
stat
| Command | Purpose |
|---|---|
stat FILE | Show file info |
stat -f PATH | Show filesystem info |
stat -t FILE | Terse, one line |
stat -L FILE | Follow symlinks |
stat -c %s FILE | Size only |
stat -c %i FILE | Inode only |
stat -c %a FILE | Octal permissions |
stat -c %U FILE | Owner name |
stat -c %G FILE | Group name |
stat -c %y FILE | Modify time |
Format Specifiers
| Specifier | Meaning |
|---|---|
%n | File name |
%s | Size in bytes |
%b | Blocks allocated |
%i | Inode number |
%h | Hard link count |
%a | Permissions (octal) |
%A | Permissions (human) |
%u | User ID |
%U | User name |
%g | Group ID |
%G | Group name |
%x | Access time |
%y | Modify time |
%z | Change time |
%w | Birth time |
%F | File type |
Inodes
| Command | Purpose |
|---|---|
stat -c %i FILE | Show inode number |
ls -i FILE | Show inode with ls |
ls -i | Show inodes for all files |
df -i | Inode usage per filesystem |
find / -inum N | Find file by inode |
find . -inum N -delete | Delete file by inode |
ln FILE HARDLINK | Create hard link (same inode) |
ln -s FILE SYMLINK | Create symlink (different inode) |
Best Practices
โ Do This:
# Use stat -c for scripting (clean output)
stat -c %s file.txt # โ
# Check inode usage on servers
df -i # โ
# Use find -inum for weird filenames
find . -inum 1234567 -delete # โ
# Compare inodes to detect hard links
stat -c '%i %n' file1 file2 # โ
# Use stat -f for filesystem info
stat -f /home # โ
# Follow symlinks with -L when needed
stat -L symlink.txt # โ
โ Don’t Do This:
# Don't confuse inode with file contents
stat -c %i file.txt # โ
inode number
# cat file.txt # โ that's contents
# Don't assume all filesystems have fixed inode counts
# (btrfs and others allocate dynamically) # โ ๏ธ
# Don't edit inode numbers manually
# (never do this โ it's a filesystem structure) # โ
# Don't ignore inode exhaustion
# Even with disk space free, you can't write files # โ ๏ธ
# Don't use stat -f on a file โ use a filesystem path
stat -f file.txt # โ shows containing FS
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| Confusing size and blocks | Different numbers | Size = bytes, Blocks = disk allocation |
| Inode vs filename | Can’t find inode | Inodes don’t store names โ use find -inum |
df -i full but df -h free | Out of inodes | Delete many small files |
| Hard link confusion | Two names, one inode | stat -c %i to verify |
| Symlink vs hard link | Different inode counts | stat -c '%i %h' |
Birth not shown | Filesystem lacks it | Not all FS store creation time |
Change โ Modify | Confused timestamps | Change = metadata; Modify = content |
stat -f on a file | Shows filesystem, not file | Use stat FILE for file info |
Real-World Examples
1. Inspect a File in Detail
$ stat /etc/hosts
File: /etc/hosts
Size: 221 Blocks: 8 IO Block: 4096 regular file
Device: 803h/2051d Inode: 131074 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-01-15 10:30:00.000000000 +0000
Modify: 2024-01-10 08:00:00.000000000 +0000
Change: 2024-01-10 08:00:00.000000000 +0000
Birth: 2023-12-01 09:00:00.000000000 +0000
2. Check Filesystem Usage
$ stat -f /home
File: "/home"
ID: 1234567890abcdef Namelen: 255 Type: ext2/ext3
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 26214400 Free: 20000000 Available: 19000000
Inodes: Total: 6553600 Free: 6000000
3. Find a File by Inode
$ find / -inum 131074 2>/dev/null
/etc/hosts
4. Verify Hard Links
$ ln /etc/hosts ~/hosts-link
$ stat -c '%i %h %n' /etc/hosts ~/hosts-link
131074 2 /etc/hosts
131074 2 /home/kronos/hosts-link
5. Detect Symlinks
$ ln -s /etc/hosts ~/hosts-symlink
$ stat -c '%i %F %n' /etc/hosts ~/hosts-symlink
131074 regular file /etc/hosts
131200 symbolic link /home/kronos/hosts-symlink
6. Check Inode Usage Across Filesystems
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda2 6553600 456789 6096811 7% /
tmpfs 408123 1234 406889 1% /run
/dev/sdb1 61054976 123456 60931520 1% /home
7. Script-Friendly Size Check
$ SIZE=$(stat -c %s file.txt)
$ echo "Size: $SIZE bytes"
Size: 1024 bytes
8. Get Modification Time for a Backup Script
$ MTIME=$(stat -c %Y file.txt)
$ NOW=$(date +%s)
$ AGE=$(( (NOW - MTIME) / 86400 ))
$ echo "File is $AGE days old"
File is 3 days old
9. Find All Files with a Specific Inode in a Directory
$ for f in *; do
printf '%s\t%s\n' "$(stat -c %i "$f")" "$f"
done | sort -n
1234567 file.txt
1234568 notes.txt
1234569 todo.txt
10. Delete a File with a Weird Name
# File created with a name like "-rf" or with newlines
$ ls -i
1234567 -rf
$ find . -inum 1234567 -delete
# โ
safely removed
11. Check If Two Paths Are the Same File
$ [ "$(stat -c %i /path/a)" = "$(stat -c %i /other/b)" ] && echo "same inode"
same inode
12. Monitor Inode Growth in a Directory
$ stat -c '%i %n' /var/log/* | wc -l
123
Visual: Filename vs Inode vs Data
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Directory โ
โ โ
โ "file.txt" โโโบ inode 1234567 โ
โ "hardlink" โโโบ inode 1234567 (same!) โ
โ "symlink" โโโบ inode 1234999 (own file) โ
โ โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Inode 1234567 โ
โ โ
โ Metadata: โ
โ Permissions: 0644 โ
โ Owner: kronos (1000) โ
โ Size: 1024 โ
โ Links: 2 (file.txt + hardlink) โ
โ Access/Modify/Change/Birth timestamps โ
โ โ
โ Data block pointers: โ
โ โโโบ block 100 (first 4096 bytes) โ
โ โโโบ block 101 (next 4096 bytes) โ
โ โโโบ ... โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Command | Purpose | Example |
|---|---|---|
stat FILE | Show file metadata | stat file.txt |
stat -f PATH | Show filesystem info | stat -f ~/CLI/ |
stat -t FILE | Terse output | stat -t file.txt |
stat -L FILE | Follow symlinks | stat -L symlink.txt |
stat -c %s FILE | Size only | stat -c %s file.txt |
stat -c %i FILE | Inode number | stat -c %i file.txt |
stat -c %a FILE | Octal permissions | stat -c %a file.txt |
stat -c %U FILE | Owner | stat -c %U file.txt |
stat -c %y FILE | Modify time | stat -c %y file.txt |
ls -i | Show inodes | ls -i |
df -i | Inode usage | df -i |
find / -inum N | Find by inode | find / -inum 1234567 |
find . -inum N -delete | Delete by inode | find . -inum 1234567 -delete |
Key takeaways:
statshows file metadata: size, blocks, inode, links, permissions, ownership, and four timestamps- Use
stat -ffor filesystem-level info (block size, free blocks, inode counts) - Use
stat -c FORMATfor scripting โ clean, parseable output - Inodes are the real objects behind filenames โ they hold metadata and point to data blocks
- Inodes do not store filenames โ directory entries do
- Hard links share an inode (same number, higher link count)
- Symlinks have their own inode and point to another path
- Inodes are assigned at creation and stay with the file until it’s deleted
df -ishows inode usage โ you can run out of inodes even with free disk space- Use
find -inumto locate or delete files by inode, especially with weird filenames
Remember: A filename is just a label. The inode is the file. stat shows you what the filesystem knows; ls -i and df -i show you the inode side of things. Hard links share an inode; symlinks don’t. Watch inode usage on servers with many small files. And when a filename is broken, spaces, newlines, or dashes, find -inum is your escape hatch.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!