24 ways to check the status of files using if commands on Linux
There are a lot more ways to check files using if commands than many of us realize. Although this information is included in the bash man page, that man page has thousands of lines and you could easily find yourself paging down more than 100 times to reach it.
This post, provides information on each option and examples for some of the most useful ones.
Checking if a file exists
One of the most commonly used tests for checking on files is if [ -f filename ]. This test will result in true if the file exists and is a regular file—not a directory or a symbolic link. You might use it like this:
$ if [ -f myfile.txt ]; then > echo myfile.txt exists > else > touch myfile.txt > fi myfile.txt exists
The command above would create the file using the touch command if it doesn’t already exist. The following command would only tell you if the file is or isn’t a regular file:
$ if [ -f /home/shs ]; then > echo file exists > else > echo file is not a regular file > fi file is not a regular file
If you want to know whether a file exists regardless of what kind of file it is, you can use the -a or the -e test.
$ if [ -e symlink ]; then > echo file exists > else > echo no such file > fi
file exists
Checking if a file is a directory
Using -d will tell you if a file is a directory.
$ if [ -d /home/shs ]; then > echo directory > else > echo not a directory > fi directory
Reversing the effect of if tests
You can reverse the effects of an if test by preceding the test with a ! (not) sign. To test if a file has content, you could use a command like this one:
$ if [ -s emptyfile ]; then > echo has content > else > echo empty > fi
To change the command above to test whether the file is empty, do this:
$ if [ ! -s emptyfile ]; then > echo empty > else > echo has content > fi
This of -s as “some content” and ! -s as “no content”.
The ! can be used with any of the if tests. Here are a few examples:
if [ ! -d file ] <— file is not a directory if [ ! -e file ] <— file doesn’t exist if [ ! -r file ] <— file is not readable
Checking file permissions
Other especially useful tests can tell you if you can read a file, write to a file or execute a file.
$ if [ -r ~/bin/loop ]; then > echo readable > fi readable
$ if [ -w ~/bin/loop ]; then > echo writable > fi writable
$ if [ -x ~/bin/loop ]; then > echo executable > fi executable
Note that these tests only check your access rights, not anyone else’s and that the files tested above are all in the bin directory in the user’s home directory (~/bin).
You can also check whether a file is a character-special file, if its SGID (set group ID) bit is set and if its SUID (set user ID) bit is set. The chmod command sets the bits being tested in the second and third examples.
$ if [ -c /dev/tty11 ]; then > echo character-special file > fi character-special file
$ chmod 7755 yn $ if [ -g yn ]; then > echo SGID set > fi SGID set
$ if [ -u yn ]; then > echo SUID set > fi SUID set
Checking if a file was recently modified
The -N checks whether a file’s content was modified since the last time it was read. The echo command below adds a line, so the second test result is the opposite of the first.
$ if [ -N testfile ]; then > echo file has been modified > else > echo file not modified > fi file not modified
$ echo “——-“ >> testfile $ $ if [ -N testfile ]; then > echo file has been modified > else > echo file not modified > fi file has been modified
Comparing file ages
You can use if tests to determine if one file has been changed more recently than another. The -nt test means “newer than”.
$ if [ file1 -nt file2 ]; then > echo file1 is newer > else > echo file2 is newer > fi file2 is newer
Using -ot (older than) in place of -nt has the opposite effect.
All if commands for checking the status of files
Here is a list of all the if tests that check the status of files. Just remember that any can be reversed with a ! symbol (e.g., if [ ! file1 -ot file2 ]).
- if [ -a FILE ] — True if FILE exists
- if [ -b FILE ] — True if FILE exists and is a block-special file
- if [ -c FILE ] — True if FILE exists and is a character-special file
- if [ -d FILE ] — True if FILE exists and is a directory
- if [ -e FILE ] — True if FILE exists
- if [ -f FILE ] — True if FILE exists and is a regular file
- if [ -g FILE ] — True if FILE exists and its SGID bit is set
- if [ -h FILE ] — True if FILE exists and is a symbolic link
- if [ -k FILE ] — True if FILE exists and its sticky bit is set
- if [ -p FILE ] — True if FILE exists and is a named pipe (FIFO)
- if [ -r FILE ] — True if FILE exists and is readable
- if [ -s FILE ] — True if FILE exists and has a size greater than zero
- if [ -t FD ] — True if file descriptor FD is open and refers to a terminal
- if [ -u FILE ] — True if FILE exists and its SUID (set user ID) bit is set
- if [ -w FILE ] — True if FILE exists and is writable
- if [ -x FILE ] — True if FILE exists and is executable
- if [ -O FILE ] — True if FILE exists and is owned by the effective user ID
- if [ -G FILE ] — True if FILE exists and is owned by the effective group ID
- if [ -L FILE ] — True if FILE exists and is a symbolic link
- if [ -N FILE ] — True if FILE exists and has been modified since it was last read
- if [ -S FILE ] — True if FILE exists and is a socket
- if [ FILE1 -nt FILE2 ] — True if FILE1 has been changed more recently than FILE2 or if FILE1 exists and FILE2 does not
- if [ FILE1 -ot FILE2 ] — True if FILE1 is older than FILE2 or if FILE2 exists and FILE1 does not
- if [ FILE1 -ef FILE2 ] — True if FILE1 and FILE2 refer to the same device and inode numbers
<!—
if test | result |
[ -a FILE ] | True if FILE exists |
[ -b FILE ] | True if FILE exists and is a block-special file |
[ -c FILE ] | True if FILE exists and is a character-special file |
[ -d FILE ] | True if FILE exists and is a directory |
[ -e FILE ] | True if FILE exists |
[ -f FILE ] | True if FILE exists and is a regular file |
[ -g FILE ] | True if FILE exists and its SGID bit is set |
[ -h FILE ] | True if FILE exists and is a symbolic link |
[ -k FILE ] | True if FILE exists and its sticky bit is set |
[ -p FILE ] | True if FILE exists and is a named pipe (FIFO) |
[ -r FILE ] | True if FILE exists and is readable |
[ -s FILE ] | True if FILE exists and has a size greater than zero |
[ -t FD ] | True if file descriptor FD is open and refers to a terminal |
[ -u FILE ] | True if FILE exists and its SUID (set user ID) bit is set |
[ -w FILE ] | True if FILE exists and is writable |
[ -x FILE ] | True if FILE exists and is executable |
[ -O FILE ] | True if FILE exists and is owned by the effective user ID |
[ -G FILE ] | True if FILE exists and is owned by the effective group ID |
[ -L FILE ] | True if FILE exists and is a symbolic link |
[ -N FILE ] | True if FILE exists and has been modified since it was last read |
[ -S FILE ] | True if FILE exists and is a socket |
[ FILE1 -nt FILE2 ] | True if FILE1 has been changed more recently than FILE2 or if FILE1 exists and FILE2 does not |
[ FILE1 -ot FILE2 ] | True if FILE1 is older than FILE2 or if FILE2 exists and FILE1 does not |
[ FILE1 -ef FILE2 ] | True if FILE1 and FILE2 refer to the same device and inode numbers |
—>
Wrap-Up
There are a lot of ways to check and verify files on the command line or within scripts. Some of these options can help ensure that your scripts check files before trying to use them or avoid overwriting them if they already exist. These tests often play an important role when using scripts to automate your work.
Copyright © 2022 IDG Communications, Inc.