How to Check If a File Exists in Linux Bash Scripts

Estimated read time 8 min read

[ad_1]

Linux laptop showing a bash prompt
fatmawati achmad zaenuri/Shutterstock.com

If a Linux Bash script relies on certain files or directories being present, it can’t just assume they do. It needs to check that they’re definitely present. Here’s how to do that.

Don’t Assume Anything

When you’re writing a script you can’t make assumptions about what is and isn’t present on a computer. That’s doubly true if the script is going to be distributed and run on many different computers. Sooner or later, the script will run on a computer that doesn’t meet your assumptions, and the script will fail or run unpredictably.

Everything we value or create on a computer is stored in a file of some format, and all of those files reside in a directory. Scripts can read, write, rename, delete and move files and directories—all the things you can do on the command line.

The advantage you have as a human is that you can see the contents of a directory and you know if a file exists or not—or whether the expected directory even exists. If a script fouls up when it is manipulating files, it can have serious and damaging results.

Bash provides a comprehensive set of tests that you can use to detect files and directories, and test for many of their attributes. Incorporating these into scripts is easy, but the benefits in terms of robustness and fine control are considerable.

RELATED: How to Use Double Bracket Conditional Tests in Linux

The Range of Tests

By combining the if statement with the appropriate test from a large collection of file and directory tests, we can easily determine if a file exists, if it’s executable, or writable, and much more.

  • -b: Returns true if the file is a block special file.
  • -c: Returns true if the file is character special.
  • -d: Returns true if the “file” is a directory.
  • -e: Returns true if the file exists.
  • -f: Returns true if the file exists and is a regular file.
  • -g: Returns true if the file has the setgid permission set (chmod g+).
  • -h: Returns true if the file is a symbolic link.
  • -L: Returns true if the file is a symbolic link.
  • -k: Returns true if has its sticky bit set (chmod +t).
  • -p: Returns true if the file is a named pipe.
  • -r: Returns true if the file is readable.
  • -s: Returns true if the files exists and isn’t empty.
  • -S: Returns true if the file is a socket.
  • -t: Returns true if the file descriptor is opened in a terminal.
  • -u: Returns true if the file has the setuid permission set (chmod u+).
  • -w: Returns true if the file is writable.
  • -x: Returns true if the file is executable.
  • -O: Returns true if the is owned by you.
  • -G: Returns true if the is owned by your group.
  • -N: Returns true if the file has been modified since it was last read.
  • !: The logical NOT operator.
  • &&: The logical AND operator.
  • ||: The logical OR operator.

The list starts with -b because the -a test has been deprecated and replaced by the -e test.

RELATED: How to Use SUID, SGID, and Sticky Bits on Linux

Using the Tests in Scripts

The generic file test if statement is a simple scripting construct. The comparison inside the double brackets ” [[ ]] ” uses the -f test to determine whether a regular file exists with that name.

Copy the text of this script into an editor and save it into a file called “script1.sh”, and use chmod to make it executable.

#!/bin/bash

if [[ -f $1 ]] 

then 

  echo "The file $1 exists." 

else 

  echo "The file $1 cannot be found." 

fi

You have to pass the name of the file to the script on the command line.

chmod +x script1.sh

Making a script executable with chmod

You’ll need to do this with each script if you want to try the other examples from the article.

Let’s try the script on a straightforward text file.

./script1.sh test-file.txt

Running script1.sh on a regular file

The file exists and the script correctly reports that fact. If we delete the file and try again, the test should fail and the script should report that to us.

./script1.sh test-file.txt

Running script1.sh against a file that doesn't exist

In a real-life situation, your script would need to take whatever action was appropriate. Perhaps it flags the error and stops. Maybe it creates the file and carries on. It may copy something out of a backup directory to replace the missing file. It all depends on the purpose of the script. But at least now the script is able to make the decision based on knowing if the file is present or not.

The -f flag tests whether the file is present, and is a “regular” file. In other words, it isn’t something that appears to be a file but isn’t, such as a device file.

We’ll use ls to verify that the “/dev/random” file exists, and then see what the script makes of it.

ls -lh /dev/random
./script /dev/random

Running script1.sh against a device file

Because our script is testing for regular files and “/dev/random” is a device file, the test fails. Very often, to get to the bottom of whether a file exists you need to carefully choose which test you use, or you need to use several tests.

This is “script2.sh”, which tests for regular files and for character device files.

#!/bin/bash

if [[ -f $1 ]]
then
  echo "The file $1 exists."
else
  echo "The file $1 is missing or not a regular file."
fi

if [[ -c $1 ]]
then
  echo "The file $1 is a character device file."
else
  echo "The file $1 is missing or not a special file." 
fi

If we run this script on the “/dev/random” device file the first test fails which we expect, and the second test succeeds. It recognizes the file as a device file.

./script2.sh /dev/random

Running script2.sh against a character device file

Actually, it recognizes it as a character device file. Some device files are block device files. As it stands, our script won’t cope with those.

./script2.sh /dev/sda

Running scrip2.sh against a block device file

We can make use of the logical OR operator and include another test in the second if statement. This time, whether the file is a character device file or a block device file, the test will return true. This is “script3.sh.”

#!/bin/bash

if [[ -f $1 ]]
then
  echo "The file $1 exists."
else
  echo "The file $1 is missing or not a regular file."
fi

if [[ -c $1 || -b $1 ]]
then
  echo "The file $1 is a character or block device file."
else
  echo "The file $1 is missing or not a special file." 
fi

This script recognizes both character device and block device files.

./script3.sh /dev/random
./script3.sh /dev/sda

script3.sh correctly handling character and block device files

If it is important to you to differentiate between the different types of device files, you can use nested if statements. This is “script4.sh.”

#!/bin/bash

if [[ -f $1 ]]
then
  echo "The file $1 exists."
else
  echo "The file $1 is missing or not a regular file."
fi

if [[ -c $1 ]]
then
  echo "The file $1 is a character device file."
else
  if [[ -b $1 ]]
  then
    echo "The file $1 is a block device file." 
  else
    echo "The file $1 is missing or not a device file."
  fi
fi

This script recognizes and categorizes both character device and block device files.

./script4.sh /dev/random
./script4.sh /dev/sda

script8.sh correctly identifying character and block device files

Using the logical AND operator we can test for several characteristics at once. This is “script5.sh.” It checks that a file exists and the script has read and write permissions for it.

#!/bin/bash

if [[ -f $1 && -r $1 && -w $1 ]]
then
  echo "The file $1 exists and we have read/write permissions."
else
  echo "The file $1 is missing, not a regular file, or we can't read/write to it."
fi

We’ll run the script on a file that belongs to us, and one that belongs to root.

./script5.sh .bashrc
./script5.sh /etc/fstab

script5.sh checking whether a file exists and whether the read and write permissions are set

To test for the existence of a directory, use the -d test. This is “script6.sh.” It is part of a backup script. The first thing it does is check whether the directory passed on the command line exists or not. It uses the logical NOT operator ! in the if statement test.

#!/bin/bash

if [[ ! -d $1 ]]
then
  echo "Creating backup directory:" $1
  mkdir $1

  if [[ ! $? -eq 0 ]]
  then
    echo "Couldn't create backup directory:" $1
    exit
  fi
else
  echo "Backup directory exists."
fi

# continue with file backup
echo "Backing up to: "$1

If the directory doesn’t exist it creates it. If the directory creation files, the script exits. If the creation of the directory succeeds, or the directory already exists, the script continues with its backup actions.

We’ll run the script and then check with ls and the -d (directory) option whether the backup directory exists.

./script6.sh Documents/project-backup
ls -d Documents/project-backup

script6.sh detecting whether a directory exists

The backup directory was created. If we run the script again, it should report that the directory is already present.

./script6.sh

script6.sh reusing an existing directory

The script finds the directory and moves on to perform the backup.

Test, Don’t Assume

Sooner or later, assumptions will lead to bad things happening. Test first, and react accordingly.

Knowledge is power. Use tests to give your scripts the knowledge they need.

RELATED: How to Let Linux Scripts Detect They’re Running in Virtual Machines



[ad_2]

Source link

You May Also Like

More From Author