Home / Alt manpages / stat(1)

  • stat(1)
  • User command
  • linux

Inspect File and Filesystem Metadata with stat

You will finish with a small set of stat commands for checking a file, distinguishing a symbolic link from its target, reading filesystem capacity, and extracting stable fields for scripts. The examples use GNU coreutils 9.4, installed here as package version 9.4-3ubuntu6.3.

Allow about fifteen minutes. You need a shell and a readable path. The checks are normally unprivileged. Use elevated privileges only when the path itself is inaccessible, and do not use sudo to make an uncertain path or result look successful.

1. Check the installed command

Start by confirming which executable your shell will run and which version it provides:

$ command -v stat
/usr/bin/stat
$ stat --version | head -1
stat (GNU coreutils) 9.4

A shell can provide its own command with the same name. The full path and version check make the examples reproducible. If your output identifies a different implementation, read that implementation's help before copying GNU-specific format strings.

Checkpoint: confirm the syntax available on this machine:

$ stat --help | sed -n '1,18p'
Usage: stat [OPTION]... FILE...
Display file or file system status.

  -L, --dereference     follow links
  -f, --file-system     display file system status instead of file status
  -c, --format=FORMAT   use the specified FORMAT instead of the default
      --printf=FORMAT   like --format, but interpret backslash escapes
  -t, --terse           print the information in terse form

The exact help text can gain or lose surrounding lines between releases. The options used here are the ones documented by the installed GNU command.

2. Read ordinary file metadata

Run stat with a path to see the default, human-readable report. Replace the placeholder with a file you expect to exist:

$ stat /path/to/report.txt
  File: /path/to/report.txt
  Size: 6          Blocks: 8          IO Block: 4096   regular file
Device: ...        Inode: ...         Links: 1
Access: (0644/-rw-r--r--)  Uid: (...)  Gid: (...)
Access: 2026-09-27 04:20:02.004665628 +0100
Modify: 2026-09-27 04:20:02.004665628 +0100
Change: 2026-09-27 04:20:02.004665628 +0100
 Birth: 2026-09-27 04:20:02.004665628 +0100

Your device, inode, account names and times will differ. Size is the file length in bytes. Blocks is allocated storage reported in filesystem blocks, so it is not a second spelling of the file size. Access shows permission bits and the last access time, Modify is the last data modification, and Change is the last metadata or content status change. Birth time is shown as - when the filesystem does not provide it.

If the path is wrong, GNU stat exits non-zero and reports the error. Check the path with ls -ld -- /path/to/report.txt; do not immediately add sudo, because changing identity can hide an ownership or deployment problem.

By default, stat reports the link itself. This matters when a service path, configuration file or release directory may be a symlink:

$ stat /path/to/current
  File: /path/to/current -> release-2026-09-27
  Size: 16         Blocks: 0          IO Block: 4096   symbolic link
Device: ...        Inode: ...         Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (...)  Gid: (...)

The link's reported size is the length of its target text, not the size of the target file. Use -L or --dereference when you need the target's metadata instead:

$ stat -L -c 'type=%F size=%s owner=%U modified=%y' /path/to/current
type=regular file size=1048576 owner=andy modified=2026-09-27 04:20:02.004665628 +0100

Checkpoint: decide which object your question concerns. Use plain stat to audit the link, and stat -L to audit what the link resolves to. A dangling link fails when dereferenced, even though the link itself can still be inspected.

4. Select fields for a script

The default report is useful for people, but scripts should request only the fields they need. GNU format sequences include %F for file type, %A for readable permissions, %a for octal permissions, %s for bytes, %U for the user name, %G for the group name, and %y for the modification time:

$ stat --printf='type=%F\nmode=%A\noctal=%a\nsize=%s\nowner=%U\ngroup=%G\nmodified=%y\n' /path/to/report.txt
type=regular file
mode=-rw-r--r--
octal=644
size=6
owner=andy
group=dixon
modified=2026-09-27 04:20:02.004665628 +0100

Use --printf when you need backslash escapes such as \n. Unlike --format, it does not add a mandatory final newline, so including one keeps command-line output tidy. A format string describes each input path, and the command prints one record per path.

For a simple gate, check the command's exit status as well as the value:

$ if stat --printf='%a\n' /path/to/report.txt; then
>     echo 'metadata read successfully'
> else
>     echo 'metadata read failed' >&2
>     exit 1
> fi
644
metadata read successfully

Do not compare human-readable timestamps or owner names when a numeric identity or an exact epoch value is the real contract. Choose the format deliberately, and quote paths that come from variables.

5. Check the filesystem behind a path

Add -f or --file-system to ask about the filesystem containing a path rather than the path object:

$ stat -f --printf='mount=%n\ntype=%T\nblock-size=%S\nfree-for-user=%a\nfree-blocks=%f\n' /path/to/report.txt
mount=/path/to/report.txt
type=ext2/ext3
block-size=4096
free-for-user=844486806
free-blocks=893104134

Filesystem format sequences have a different meaning from file format sequences. Here, %a is the number of free blocks available to an ordinary user, %f is free blocks in the filesystem, %S is the fundamental block size, and %T is the human-readable filesystem type. Do not reuse a file-oriented format string with -f and assume the values still mean the same thing.

The displayed mount field is the input name in this GNU format. If you need the actual mount point, use a mount-aware tool such as findmnt separately. A capacity check can be read-only, but acting on a low-space result may affect services, so investigate before deleting files.

6. Use terse output only when its contract suits you

--terse produces a compact, positional record:

$ stat --terse /path/to/report.txt
/path/to/report.txt 6 8 81a4 1004 1004 902 124257160 1 0 0 1790479202 1790479202 1790479202 1790479202 4096

The numbers are difficult to review and the record is tied to the documented format sequence. Prefer an explicit --printf format for new scripts, especially when a later reader needs to understand each field. If you must consume terse output, pin the GNU implementation and version in the script's operational notes.

7. Diagnose failures safely

For "No such file or directory", test the parent directory and spelling. For "Permission denied", identify the account and permissions before escalating:

$ id
$ name='/path/to/report.txt'
$ ls -ld -- "${name%/*}" "$name"
$ test -r "$name" && echo readable
readable

If the path contains no slash, ${name%/*} becomes the same string rather than a useful parent, so use an absolute or directory-qualified path while investigating. Do not change permissions, ownership or symlink targets as a diagnostic shortcut. Those changes alter system state and need a separate, reviewed operation with a recovery plan.

Done means

  • You confirmed the GNU stat implementation and installed coreutils version.
  • You can read default file metadata and interpret size, blocks and timestamps.
  • You can choose between inspecting a symlink and following it to its target.
  • Your scripts use explicit format sequences and check the command's exit status.
  • You know that -f changes the meaning of the format sequences to filesystem data.
  • You diagnosed path and permission errors without changing files or service configuration.