A Linux terminal on a Ubuntu-style desktop.
Fatmawati Achmad Zaenuri/Shutterstock

The Linux stat command shows you much more detail than ls does. Take a peek behind the curtain with this informative and configurable utility. We’ll show you how to use it.

stat Takes You Behind the Scenes

The ls command is great at what it does—and it does a lot—but with Linux, it seems that there’s always a way to go deeper and see what lies beneath the surface. And often, it isn’t just a case of lifting the edge of the carpet. You can rip up the floorboards and then dig a hole. You can peel Linux like an onion.

ls will show you a good deal of information about a file, such as which permissions are set on it, and how big it is, and whether it is a file or a symbolic link. To display this information ls reads it from a file system structure called an inode.

Every file and directory has an inode. The inode holds metadata about the file, such as which filesystem blocks it occupies, and the date stamps associated with the file. The inode is like a library card for the file. But ls will only show you some of the information. To see everything, we need to use the stat command.

Like ls , the stat command has a lot of options. This makes it a great candidate for the use of aliases. Once you have discovered a particular set of options that make stat give you the output that you want, wrap it in an alias or shell function. This makes it much more convenient to use, and you don’t have to remember an arcane set of command-line options.

RELATED: How to Use the ls Command to List Files and Directories on Linux

A Quick Comparison

Let’s use ls to give us a long listing ( -l option) with human-readable file sizes ( -h option):

ls -lh ana.h

ls -lh ana.h in a terminal window

From left to right, the information that ls provides is:

  • The very first character is a hyphen “-” and this tells us the file is a regular file and not a socket, symlink, or another type of object.
  • The owner, group, and other permissions are listed in octal format.
  • The number of hard links pointing to this file. In this case, and in most cases, it will be one.
  • The file owner is dave.
  • The group owner is dave.
  • The file size is 802 bytes.
  • The file was last modified on Friday, 13th December 2015.
  • The file name is ana.c.

Let’s take a look with stat :

stat ana.h

stat ana.h in a terminal window

The information we get from stat is:

  • File: The name of the file. Usually, it is the same as the name we passed to stat on the command line, but It can be different if we’re looking at a symbolic link.
  • Size: The size of the file in bytes.
  • Blocks: The number of filesystem blocks the file requires, in order to be stored on the hard drive.
  • IO Block: The size of a filesystem block.
  • File type: The type of object the metadata describes. The most common types are files and directories, but they can also be links, sockets, or named pipes.
  • Device: The device number in hexadecimal and decimal. This is the ID of the hard drive the file is stored on.
  • Inode: The inode number. That is, the ID number of this inode. Together, the inode number and the device number uniquely identify a file.
  • Links: This number indicates how many hard links point to this file. Each hard link has its own inode. So another way to think about this figure is how many inodes point to this one file. Each time a hard link is created or deleted, this number will be adjusted up or down. When it reaches zero, the file itself has been deleted, and the inode is removed. If you use stat on a directory, this number represents the number of files in the directory, including the “.” entry for the current directory and the “..” entry for the parent directory.
  • Access: The file permissions are shown in their octal and traditional rwx (read, write, execute formats).
  • Uid: User ID and account name of the owner.
  • Gid: Group ID and account name of the owner.
  • Access: The access timestamp. Not as straightforward as it might seem. Modern Linux distributions use a scheme called relatime, which tries to optimize the hard drive writes required to update the access time. Simply put, the access time is updated if it is older than the modified time.
  • Modify: The modification timestamp. This is the time when file’s contents were last modified. (As luck would have it, the contents of this file were last changed four years ago to the day.)
  • Change: The change timestamp. This is the time the file’s attributes or contents were last changed. If you modify a file by setting new file permissions, the change timestamp will be updated (because the file attributes have changed), but the modified timestamp will not be updated (because the file contents were not changed).
  • Birth: Reserved to show the original creation date of the file, but this is not implemented in Linux.

Understanding the Timestamps

The timestamps are timezone sensitive. The -0500 at the end of each line shows that this file was created on a computer in a Coordinated Universal Time (UTC) timezone that is five hours ahead of the timezone of the current computer. So this computer is five hours behind the computer that created this file. In fact, the file was created on a UK timezone computer, and we’re looking at it here on a computer in the US Eastern Standard time zone.

The modify and change timestamps can cause confusion because, to the uninitiated, their names sound as if they mean the same thing.

Let’s use chmod to modify the file permissions on a file called ana.c. We’re going to make it writeable by everyone. This won’t affect the contents of the file, but it will affect the attributes of the file.

chmod +w ana.c

And then we’ll use stat to look at the timestamps:

stat ana.c

chnod +w ana.c in a terminal window

The change timestamp has been updated, but the modified one has not.

The modified timestamp will only be updated if the contents of the file are changed. The change timestamp is updated for both content changes and attribute changes.

Using Stat With Multiple Files

To have stat report on several files at once, pass the filenames to stat on the command line:

stat ana.h ana.o

stat ana.h ana.o in a terminal window

To use stat on a set of files, use pattern matching. The question mark “?” represents any single character, and the asterisk “*” represents any string of characters. We can tell stat to report on any file called “ana” with a single letter extension, with this command:

stat ana.?

stat ana.? in a terminal window

Using stat to Report on Filesystems

stat can report on the status of filesystems, as well as the status of files. The -f (filesystem) option tells stat to report on the filesystem that the file resides on. Note we can also pass a directory such as “/” to stat instead of a filename.

stat -f ana.c

stat -f ana.c ina terminal window

The information stat gives us is:

  • File: The name of the file.
  • ID: The filesystem ID in hexadecimal notation.
  • Namelen: The maximum permissible length for file names.
  • Type: The type of filesystem.
  • Block size: The amount of data to request read requests for optimum data transfer rates.
  • Fundamental block size: The size of each filesystem block.

Blocks:

  • Total: The total count of all blocks n the filesystem.
  • Free: The number of free blocks in the filesystem.
  • Available: The number of free blocks available to regular (non-root) users.

Inodes:

  • Total: The total count of inodes in the filesystem.
  • Free: The number of free inodes in the filesystem.

Dereferencing Symbolic Links

If you use stat on a file that is actually a symbolic link, it will report on the link. If you wanted stat to report on the file that the link points to, use the -L (dereference) option. The file code.c is a symbolic link to ana.c . Let’s look at it without the -L option:

stat code.c

stat code.c in a terminal window

The filename shows code.c pointing to ( -> ) ana.c. The file size is only 11 bytes. There are zero blocks devoted to storing this link. The file type is listed as a symbolic link.

Clearly, we’re not looking at the actual file here. Let’s do that again and add the -L option:

stat -L code.c

stat -L code.c  in a terminal window

This is now showing the file details for the file pointed to by the symbolic link.  But note that the filename is still given as code.c. This is the name of the link, not the target file. This happens because this is the name we passed to stat on the command line.

The Terse Report

The -t (terse) option causes stat to provide a condensed summary:

stat -t ana.c

stat -t ana.c in a terminal window

There are no clues given. To make sense of it—until you’ve memorized the field sequence—you need to cross-reference this output to a full stat output.

Custom Output Formats

A better way to obtain a different set of data from stat is to use a custom format. There is a long list of tokens called format sequences. Each of these represents a data element. Select the ones you want to have included in the output and create a format string. When we call stat and pass the format string to it, the output will only include the data elements we requested.

There are different sets of format sequences for files and filesystems. The list for files is:

  • %a: The access rights in octal.
  • %A: The access rights in human-readable form (rwx).
  • %b: The number of blocks allocated.
  • %B: The size in bytes of each block.
  • %d: The device number in decimal.
  • %D: The device number in hex.
  • %f: The raw mode in hex.
  • %F  The file type.
  • %g: The group ID of the owner.
  • %G: The group name of the owner.
  • %h: The number of hard links.
  • %i: The inode number.
  • %m: The mount point.
  • %n: The file name.
  • %N: The quoted file name, with dereferenced filename if it is a symbolic link.
  • %o: The optimal I/O transfer size hint.
  • %s: The total size, in bytes.
  • %t: The major device type in hex, for character/block device special files.
  • %T: The minor device type in hex, for character/block device special files.
  • %u: The user ID of the owner.
  • %U: The user name of the owner.
  • %w: The time of file birth, human-readable, or a hyphen “-” if unknown.
  • %W:  The time of file birth, seconds since the Epoch; 0 if unknown.
  • %x: The time of last access, human-readable.
  • %X: The time of last access, seconds since the Epoch.
  • %y: The time of last data modification, human-readable.
  • %Y: The time of last data modification, seconds since the Epoch.
  • %z: The time of last status change, human-readable.
  • %Z: The time of last status change, seconds since the Epoch.

The “epoch” is the Unix Epoch, which took place on 1970-01-01 00:00:00 +0000 (UTC).

For filesystems the format sequences are:

  • %a: The number of free blocks available to regular (non-root) users.
  • %b: The total data blocks in the filesystem.
  • %c: The total inodes in the filesystem.
  • %d: The number of free inodes in the filesystem.
  • %f: The number of free blocks in the filesystem.
  • %i: The file system ID in hexadecimal.
  • %l: The maximum length of filenames.
  • %n: The filename.
  • %s: The block size (the optimum writing size).
  • %S: The size of filesystem blocks (for block counts).
  • %t: The file system type in hexadecimal.
  • %T: file system type in human-readable form.

There are two options that accept strings of format sequences. These are --format and --printf. The difference between them is --printf interprets C-style escape sequences such as newline \n and tab \t , and it does not automatically add a newline character to its output.

Let’s create a format string and pass it to stat. The format sequences were going to use are %n for filename, %s for the size of the file and %F for the file type. We’re going to add the \n escape sequence to the end fo the string to make sure each file is handled on a new line. Our format string looks like this:

"File %n is %s bytes, and is a %F\n"

We’re going to pass this to stat using the --printf option. We’re going to ask stat to report on a file called code.c and a set of files that match ana.?. This is the full command. Note the equals sign “=” between --printf and the format string:

stat --printf="File %n is %s bytes, and is a %F\n" code.c ana/ana.?

stat --printf="File %n is %s bytes, and is a %F\n" code.c ana/ana.? in a terminal window

The report for each file is listed on a new line, which is what we requested. The filename, file size, and file type are provided for us.

Custom formats give you access to even more data elements than are included in the standard stat output.

Fine Grain Control

As you can see, there is tremendous scope to extract the particular data elements that are of interest to you. You can probably also see why we recommended using aliases for the longer and more complex incantations.

Dave McKay Dave McKay
Dave McKay first used computers when punched paper tape was in vogue, and he has been programming ever since. After over 30 years in the IT industry, he is now a full-time technology journalist. During his career, he has worked as a freelance programmer, manager of an international software development team, an IT services project manager, and, most recently, as a Data Protection Officer. Dave is a Linux evangelist and open source advocate.
Read Full Bio »

The above article may contain affiliate links, which help support How-To Geek.