Learn how to use the Linux stat command to view detailed file metadata, timestamps, permissions, and filesystem information. This comprehensive tutorial covers everything you need to know about the stat command and how it differs from the ls command.
The stat command is an essential Linux tool that displays comprehensive information about files and filesystems – far more detailed than what ls shows. In this tutorial, I’ll show you how to view file metadata, format stat output, filter by timestamps, and analyze filesystem details.
Basic File Information
To get started, I have a text file in my current working directory that I’ll use for the first example. It contains a list of commands for the Nextcloud video that I’m working on.
ls
As I mentioned during the intro, we can use the stat command to view metadata information about a file, including information that the ls command isn’t able to show. For the sake of comparison, let’s see the information that the ls command is able to print regarding this file:
ls -l commands.txt
As you probably already know, the ls command is very useful when it comes to viewing basic information about a file, and here we see the permission string, the user that owns the file, the group that’s applied to it, link count, and so on. I covered the ls command in another video in this series, so I won’t go into any more detail then that but I think it’s helpful to have a point of comparison.
So, let’s see what the stat command shows for this same file:
stat commands.txt
As you can see, the stat command reveals much more detailed information about a file than ls. Some of the fields overlap with what you’d see from ls, but many of the statistics shown here are unique to stat and aren’t available from ls at all.
Starting from the top, we see the file name and size. These values are familiar, since ls shows them as well. But we also see the Blocks field. This does not represent the file’s size in bytes — instead, it shows the number of disk allocation blocks the file consumes. Most Linux filesystems use 4 KB blocks, so a file that is only a few bytes long may still consume a full 4 KB block (or more), depending on how many blocks it needs. This makes the “Blocks” field more reflective of the file’s actual disk usage, whereas ls only shows the logical file size.
Next is the IO Block field, which shows the filesystem’s preferred block size for I/O operations — commonly 4096 bytes (4 KB). This is a filesystem-level value, not specific to the file itself.
We also see the file type, such as “regular file” in this example. That’s expected since we’re looking at a standard text file, but it’s useful when inspecting special files such as directories, devices, or sockets.
Moving down, the Device field indicates the underlying filesystem or storage device on which the file resides. This value is shown in a low-level hexadecimal format used internally by the Linux kernel. It won’t match familiar names like /dev/sda1 or /dev/nvme0n1p2, so it’s not something you’ll typically reference. It’s mainly useful for debugging or low-level filesystem work.
On the same line, we see the file’s inode number. Every file on a Linux filesystem has a unique inode number within that specific filesystem. Inodes act like identity numbers for files — they store metadata about the file, while directory entries store the file name. Two files on different devices can have the same inode number, but only by coincidence since each device maintains its own inode table. If you create a hard link, the link shares the same inode number as the original file, since both names point to the same underlying inode. I’ve covered hard links in detail in a separate video, so I won’t go deeper into that here.
Speaking of links, the Links field shows how many directory entries point to this file. Even though I haven’t created any hard links, the link count is still 1. That’s because every file begins with a link count of one—the file’s own directory entry. If you create additional hard links, this number will increase accordingly. If you want a deeper explanation of how links work, be sure to check out my dedicated video on that topic.
Moving on, the next section displays the file’s Access information. None of these fields are unique to stat; you can also view them using the ls command with the appropriate options. What stat does is simply show everything all at once. Here, we can see the traditional permission string, the numeric (octal) permission value, the file’s owner and group, and their respective user and group IDs. All of this is the same information you can get from ls -l or other permission-related options. I’ve covered permissions extensively in another video in this series, so check that out if you want a deeper dive.
The next line is specific to systems that use SELinux. Depending on your distribution, you may or may not see this line at all. If SELinux is enabled, the stat output will show the file’s SELinux context. You can view this same information using ls with the -Z option:
ls -Z commands.txt
Covering SELinux in detail is outside the scope of this article, but if you’re new to Linux and wondering what it is, Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) system built into the Linux kernel. It provides an additional layer of security on top of traditional Unix permissions by enforcing fine-grained access policies. I haven’t done a full video on SELinux yet, but I plan to, and depending on when you’re watching this, that video may already be available. Keep an eye on the channel page and consider subscribing so you don’t miss it.
Now let’s move on to the last several timestamps shown in the stat output. These fields describe when the file was accessed, modified, and changed. The terms Modify and Change might seem similar, but in Linux they refer to different events.
- Modify (mtime) refers to the last time the contents of the file were altered. If you open the file and edit even a single character, this timestamp updates.
- Change (ctime) refers to the last time the metadata of the file changed. This includes things like permissions, ownership, or the number of links. Importantly, modifying the file’s contents also updates the change time, but changing metadata does not modify the file’s contents.
In contrast, most tools that show file information—such as ls—typically display only the modification time. This can make it harder to tell whether a file’s metadata changed separately from its contents. The stat command gives us both values independently, which is especially helpful in filesystem forensics or troubleshooting, since it reveals exactly what type of change occurred.
Finally, the last line shows the file’s Birth time (also called creation time or btime). This indicates when the file was originally created, regardless of any future modifications or metadata changes. Not all filesystems support recording creation time, but on modern Linux filesystems like ext4, xfs, and btrfs, this field is usually available.
To see these timestamps in action, let’s change this file’s permissions and then run the stat command again to compare the output.
Note: Update permissions, run stat again
stat command options
With the earlier examples, the stat command showed us all available file information at once. But we don’t always need everything. Often—especially when writing scripts—it’s much more useful to extract just the fields you care about. For example, if a script only needs a file’s modification time, it’s much easier to work with clean, minimal output.
To display individual fields, we use the -c (format) option, which allows us to tell stat exactly what to print. For example:
stat -c %y commands.txt
Here, %y is the format sequence for the file’s modification time. After that, we provide the filename we want to inspect. If you want to make the output more descriptive, you can add text before the format sequence:
stat -c "Modified: %y" commands.txt
This lets anyone reading the output clearly understand what the value represents. You can use any of the fields that stat supports, and I’ll display a table on screen that lists the most common formatting sequences you may want to use.
You can also reference multiple fields at the same time:
stat -c "Access: %x, Modify: %y, Change: %z" commands.txt
In this example, we’re limiting the output to only the access, modification, and change timestamps.
To make our formatting options clearer, I’ll show a table of the common format sequences you can use. I’ll also include this table in the blog post linked in the description so you can refer to it later.
Now, the output of that last command was printed on a single line—which is the default behavior of stat. If you want the output to be easier to read, you can insert line breaks:
stat -c $'Access: %x\nModify: %y\nChange: %z\n' commands.txt
With this example, I added helpful line breaks by including \n after every field. In addition, I added a dollar sign right before the quoted string, which is required for line breaks to be work properly.
I also changed to single quotes instead of double quotes, because otherwise the output wouldn’t format correctly:
stat -c 'Access: %x\nModify: %y\nChange: %z\n' commands.txt
In this example, I added \n (newline characters) after each field. Notice the $’…’ syntax—this is required for escape sequences like \n to be interpreted correctly by Bash. Without the dollar sign, Bash prints the literal characters “\n” instead of creating real line breaks. Also notice that I’m using single quotes. With double quotes, Bash would interpret some characters differently, and the formatting would not work as intended. These details are specific to Bash’s quoting rules, not to stat itself.
By combining formatting sequences, labels, and escape characters, you can create clean, readable, and script-friendly output that shows only the information you care about.
Additional Examples
Let’s see some additional examples, and one thing I want to point out is that even though we’ve been targeting a single file with every example so far, you don’t have to provide a file name – you can also use wildcards:
stat *
stat *.txt
This isn’t the most useful example, but it demonstrates that stat can operate on multiple files at once.
Here’s a more practical example that shows the modification time and filename for all .txt files, and then sorts them by date:
stat -c "%y %n" *.txt | sort -n
With this example, we’re using the -c option and limiting output to show only the modification times, as well as file names. Then, we’re redirecting the output into the sort command, and the -n option sorts numerically. Putting this altogether, we can use a command like this to view the modification times of text files while also sorting them by date. And this is yet another example of how it can be helpful to take the output of one command and use it as input for another – chaining commands together is kind of like a super power when it comes to Linux commands.
Another useful example: finding text files that were modified today:
stat -c "%y %n" *.txt | grep $(date +%Y-%m-%d)
In this case, we’re instructing the stat command to show only the modification time as well as the file name, and we’re inspecting any file that ends with a .txt file extension. Then, we’re redirecting the output into the grep command. After the grep command we have the date command, which I covered during another video in this series. The date command is included within a dollar sign and parenthesis, which is called a subshell. Essentially, a subshell runs a command in the background and the dollar sign and parenthesis are replaced by the output of that command. In this case, when we redirect the output of stat to grep, grep is going to use the results of the date command as its criteria.
Another helpful option of the stat command is -f, which gives us filesystem information about a file:
stat -f commands.txt
As you can see, with the -f option the output of the stat command looks very different – we see different fields now. Specifically, we’re seeing information regarding the filesystem that the file resides on. For example, we see block info, as well as the type of filesystem the storage device is using, which in this case is btrfs. This is useful when you need to know something about the storage device or partition a file resides on, rather than the file itself.
Anyway, that’s about it for this article. To help you learn the stat command, I recommend that you play around with it for a bit. Try inspecting other types of files, and also limit the output to other fields. To make it easier I’ll overlay the table again that shows the fields you can use.
So, have some fun with the stat command and see what examples you can come up with, and be sure to add anything you discover to your notes so that way you’ll have useful information that you can come back to later.


