|

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.

FieldMeaning
SizeSize in bytes
BlocksTotal blocks allocated on the HDD
IO BlockSize of each block in bytes
DeviceDevice ID in hexadecimal format
InodeInode number of the file
LinksNumber of hard links
AccessFile permissions (in symbolic form)
UidOwner ID (user)
GidGroup ID
Access timeLast time the file was read
Modify timeLast time the file’s contents changed
Change timeLast time the file’s metadata changed
Birth timeWhen 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:

LineWhat 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 fileFile 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:

OptionPurpose
-fShow filesystem info instead of file info
-c FORMATCustom output format
-tTerse output (one line)
-LFollow 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:

SpecifierMeaning
%nFile name
%sSize in bytes
%bBlocks allocated
%iInode number
%hHard link count
%aPermissions (octal)
%APermissions (human)
%uUser ID
%UUser name
%gGroup ID
%GGroup name
%xAccess time
%yModify time
%zChange time
%wBirth time
%FFile 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 -i and stat let 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

CommandPurpose
stat FILEShow file info
stat -f PATHShow filesystem info
stat -t FILETerse, one line
stat -L FILEFollow symlinks
stat -c %s FILESize only
stat -c %i FILEInode only
stat -c %a FILEOctal permissions
stat -c %U FILEOwner name
stat -c %G FILEGroup name
stat -c %y FILEModify time

Format Specifiers

SpecifierMeaning
%nFile name
%sSize in bytes
%bBlocks allocated
%iInode number
%hHard link count
%aPermissions (octal)
%APermissions (human)
%uUser ID
%UUser name
%gGroup ID
%GGroup name
%xAccess time
%yModify time
%zChange time
%wBirth time
%FFile type

Inodes

CommandPurpose
stat -c %i FILEShow inode number
ls -i FILEShow inode with ls
ls -iShow inodes for all files
df -iInode usage per filesystem
find / -inum NFind file by inode
find . -inum N -deleteDelete file by inode
ln FILE HARDLINKCreate hard link (same inode)
ln -s FILE SYMLINKCreate 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

PitfallProblemSolution
Confusing size and blocksDifferent numbersSize = bytes, Blocks = disk allocation
Inode vs filenameCan’t find inodeInodes don’t store names โ€” use find -inum
df -i full but df -h freeOut of inodesDelete many small files
Hard link confusionTwo names, one inodestat -c %i to verify
Symlink vs hard linkDifferent inode countsstat -c '%i %h'
Birth not shownFilesystem lacks itNot all FS store creation time
Change โ‰  ModifyConfused timestampsChange = metadata; Modify = content
stat -f on a fileShows filesystem, not fileUse 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

CommandPurposeExample
stat FILEShow file metadatastat file.txt
stat -f PATHShow filesystem infostat -f ~/CLI/
stat -t FILETerse outputstat -t file.txt
stat -L FILEFollow symlinksstat -L symlink.txt
stat -c %s FILESize onlystat -c %s file.txt
stat -c %i FILEInode numberstat -c %i file.txt
stat -c %a FILEOctal permissionsstat -c %a file.txt
stat -c %U FILEOwnerstat -c %U file.txt
stat -c %y FILEModify timestat -c %y file.txt
ls -iShow inodesls -i
df -iInode usagedf -i
find / -inum NFind by inodefind / -inum 1234567
find . -inum N -deleteDelete by inodefind . -inum 1234567 -delete

Key takeaways:

  • stat shows file metadata: size, blocks, inode, links, permissions, ownership, and four timestamps
  • Use stat -f for filesystem-level info (block size, free blocks, inode counts)
  • Use stat -c FORMAT for 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 -i shows inode usage โ€” you can run out of inodes even with free disk space
  • Use find -inum to 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!