You might be used to being able to tell what type of file you’re working with by looking at its filename. Typically, a three or four-letter extension gives it away. For example, foo.pdf is a PDF file, logo.png is a graphics file, and foo.txt is a plain-text file. But sometimes there’s no extension, and sometimes the files are named incorrectly.
The file command can help you figure out what type of file you’re working with. Try it out by pointing it at the greetings.txt file you created in the Desktop directory within your home directory:
| $ file ~/Desktop/greetings.txt |
| /home/brian/Desktop/greetings.txt: ASCII text |
The output tells you what’s in the file by looking at its content. Create a file called test.html in your home directory with touch and try to identify it:
| $ touch ~/test.html |
| $ file ~/test.html |
| /home/brian/test.html: empty |
This time file tells you it’s an empty file, despite having the .html extension. Now throw some HTML into the file:
| $ echo '<h1>this is a test</h1>' > test.html |
| $ file test.html |
| /home/brian/test.html: ASCII text |
Now it says it’s an ASCII text file. You might have expected it to report something like “HTML file”, but that’s not quite how it works. Sure, there’s HTML in it, but find looks at the first few bytes of the file to try to determine what it is, and it isn’t quite sure.
Put an HTML5 doctype at the beginning of the file:
| $ echo '<!DOCTYPE html><h1>this is a test</h1>' > test.html |
This time, file tells you it’s an HTML document:
| $ file test.html |
| /home/brian/test.html: HTML document, ASCII text |
Since file is looking at the contents of the file instead of the filename, it’s great for figuring out files that have been mislabeled, like graphics files with a png extension that are actually jpeg files. You can use file to identify the correct type and rename the file appropriately.
The file command is great for determining the type of file, but you might want more information about the file itself, such as when it was last accessed. The ls command is fine for collecting basic information about a file, directory, or other filesystem object, but the stat command will tell you much more.
Use the stat command to view details about the test.html file you just worked with:
| $ stat test.html |
| File: test.html |
| Size: 39 Blocks: 8 IO Block: 4096 regular file |
| Device: 801h/2049d Inode: 538539 Links: 1 |
| Access: (0644/-rw-r--r--) Uid: ( 1000/ brian) Gid: ( 1000/ brian) |
| Access: 2019-03-02 16:15:26.506004475 -0600 |
| Modify: 2019-03-02 16:15:25.150004475 -0600 |
| Change: 2019-03-02 16:15:25.150004475 -0600 |
| Birth: - |
macOS Has Different Output and Options | |
---|---|
The stat command on macOS doesn’t produce the same output as the one on Ubuntu by default. Use stat -x instead, or install the GNU version on your Mac by following Installing coreutils. |
This gives you a nice detailed view of the file, its size on disk, what type of file it is (a regular file in this case), the inode, permissions, ownership, user and group IDs, and timestamps for when the file was last accessed, modified, or changed.
The Access timestamp is the last time something read the file. The Modify timestamp shows the last time the file’s contents changed. The Change timestamp reflects when the file’s inode changes, such as when permissions or other metadata about the file is updated. This can also include the file’s content.
Time to experiment. Add a line of text to the file:
| $ echo '<p>How are you today?</p>' >> test.html |
Now, run the stat command again. Since you changed the file, both the Modify and Change fields updated, but the Access timestamp did not:
| $ stat test.html |
| File: test.html |
| Size: 65 Blocks: 8 IO Block: 4096 regular file |
| Device: 801h/2049d Inode: 538539 Links: 1 |
| Access: (0644/-rw-r--r--) Uid: ( 1000/ brian) Gid: ( 1000/ brian) |
| Access: 2019-03-02 16:15:26.506004475 -0600 |
» | Modify: 2019-03-02 16:18:38.674004475 -0600 |
» | Change: 2019-03-02 16:18:38.674004475 -0600 |
| Birth: - |
Display the file with cat and run stat again. The Access timestamp has changed.
| $ cat test.html |
| $ stat test.html |
| File: test.html |
| Size: 65 Blocks: 8 IO Block: 4096 regular file |
| Device: 801h/2049d Inode: 538539 Links: 1 |
| Access: (0644/-rw-r--r--) Uid: ( 1000/ brian) Gid: ( 1000/ brian) |
» | Access: 2019-03-02 16:19:48.258004475 -0600 |
| Modify: 2019-03-02 16:18:38.674004475 -0600 |
| Change: 2019-03-02 16:18:38.674004475 -0600 |
| Birth: - |
This makes sense, since you didn’t change anything. Still, you’re probably wondering why both the Modify and Change timestamps updated when you added content, even though you only changed the file’s contents. Remember that the Change time reflects a change to the underlying inode, so a change to the content affects both the Modify time and the Change time. But if you change the permissions on the file, you’ll see that reflected only in the Change time. Give it a try. Change permissions on the file so that your user is the only person with access:
| $ chmod 700 test.html |
Now run stat again:
| $ stat test.html |
| File: test.html |
| Size: 65 Blocks: 8 IO Block: 4096 regular file |
| Device: 801h/2049d Inode: 538539 Links: 1 |
| Access: (0700/-rwx------) Uid: ( 1000/ brian) Gid: ( 1000/ brian) |
| Access: 2019-03-02 16:19:48.258004475 -0600 |
| Modify: 2019-03-02 16:18:38.674004475 -0600 |
» | Change: 2019-03-02 16:21:02.950004475 -0600 |
| Birth: - |
This time, the Change entry is the only timestamp that’s updated. Note that the output also shows the updated permissions.
The stat command works on directories as well. Run the stat command against the app directory you created in Working with Links:
| $ stat app |
| File: app |
» | Size: 4096 Blocks: 8 IO Block: 4096 directory |
| Device: 801h/2049d Inode: 534335 Links: 5 |
| ... |
This time, the output reports that you’re looking at a directory. Now run stat on the app/current directory, which is a symlink:
| $ stat app/current |
| File: app/current -> app/v3 |
» | Size: 6 Blocks: 0 IO Block: 4096 symbolic link |
| Device: 801h/2049d Inode: 538538 Links: 1 |
| ... |
The output shows you’re looking at a symlink.
You can also use stat to get information about the underlying filesystem by using the -f flag:
| $ stat -f test.html |
| File: "test.html" |
| ID: 7e65dd4d07bdafb7 Namelen: 255 Type: ext2/ext3 |
| Block size: 4096 Fundamental block size: 4096 |
| Blocks: Total: 2563397 Free: 1471084 Available: 1335942 |
| Inodes: Total: 655360 Free: 521858 |
Finally, you can control the output you want to see. On Linux versions of stat, you do this using the --printf option. For example, use this command to print out the access time:
| $ stat --printf '%x ' test.html |
| 2018-11-14 22:28:57.257636803 +0530 |
The %x value shows the human-readable access time, and adds a line break. You can add other text, as well, to create a label:
| $ stat --printf 'Access: %x ' test.html |
| Access: 2019-03-02 16:19:48.258004475 -0600 |
If you use %y and %z, you can display the modified and changed times, respectively:
| $ stat --printf 'Access: %x Modify: %y Change: %z ' test.html |
| Access: 2019-03-02 16:19:48.258004475 -0600 |
| Modify: 2019-03-02 16:18:38.674004475 -0600 |
| Change: 2019-03-02 16:21:02.950004475 -0600 |
On macOS or BSD versions of stat, you’ll use different formatting options. Use the man stat command to see the values you can display for your version of stat.
The stat command can give you insight into when a file was updated or accessed, and tell you more about the underlying filesystem, which can be very helpful when debugging a file access issue.
18.191.205.99