1. Overview

Sometimes, we may need to take action in a shell script when a particular file is created. For example, we may want to synchronize the execution of two scripts using a file. The first script waits for the second script to create the file. When the second script creates the file, it waits for the first script to delete it. As soon as the first script detects the existence of the file, it deletes it. Hence, the file’s creation and deletion act as a guard condition for the scripts. Both scripts continue execution once the file is deleted.

Of course, there might be many other cases to wait for a particular file. For example, we may just need the data in the file.

In this tutorial, we’ll discuss how to detect the creation of a file in a shell script.

2. Polling the File Periodically

The simplest way to check whether the file we’re interested in has been created is to poll the existence of the file periodically. We may use the following script, poll_existence.sh, for this purpose:

#!/bin/bash

file_to_wait=$1
while [ ! –e ${file_to_wait} ]
do
  sleep 1
done

echo “${file_to_wait} has been created”

The script gets the name of the file that we’ll wait for as input. It assigns the file name to the shell variable, file_to_wait.

Then, it checks the existence of the file using the conditional expression [ ! –e ${file_to_wait} ] in a while loop. If the conditional expression is true (i.e., the file doesn’t exist), the script sleeps for one second using sleep 1 within the while loop and rechecks the conditional expression. When the file is created, the conditional expression becomes false. The script prints that the file has been created and exits.

Let’s run the script and check the existence of the file new_file within the /tmp directory:

$ rm –f /tmp/new_file
$ poll_existence.sh /tmp/new_file

First, we deleted the file using rm –f /tmp/new_file to ensure that it didn’t exist. The script started to wait for the file.

Now, let’s create the file in another terminal using the touch command:

$ touch /tmp/new_file

When we created the file, we observed the following output in the terminal we executed the script:

$ poll_existence.sh /tmp/new_file
/tmp/new_file has been created
$

Hence, we detected the creation of the file successfully.

3. The inotifywait Command

A more efficient method to wait for a file is to use the inotifywait command in the inotify kernel subsystem. This subsystem monitors the changes in the file system and reports them. We must have already installed the inotify-tools package to use inotifywait.

3.1. Understanding the inotifywait Command

Let’s explore inotifywait using an example:

$ inotifywait –m –e create /tmp
Setting up watches.
Watches established.

The –m option causes inotifywait to execute indefinitely. Normally, inotifywait exits after the first event occurs. We may also use –monitor instead of –m.

The –e option lets us specify the events that we’re interested in. We passed the create event to the –e option in our example. Hence, we want to be notified when a file or directory is created within the watched directory.

Finally, we specified the watched directory as the last argument of inotifywait, /tmp.

Now, let’s create a file within the /tmp directory using touch. We’ll do it in a new terminal so that we can observe the output in the terminal where we executed inotifywait:

$ touch /tmp/new_file

We created a file named new_file within the /tmp directory. The /tmp directory is the directory we’re watching for events using inotifywait.

As soon as we created the file /tmp/new_file, we observed the following in the terminal we executed inotifywait:

$ inotifywait –m –e create /tmp
Setting up watches.
Watches established.
/tmp/ CREATE new_file

As it’s apparent from the last line in the output, /tmp/ CREATE new_file, inotifywait detected the creation of the file, new_file within the /tmp directory.

We can use the —format option to specify what will be printed when an event occurs within the watched directory:

$ inotifywait –m –q –e create –-format %f /tmp

The ‘%f’ passed to the –format option tells inotifywait just to print the name of the file which caused the event to occur.

We also used the –q option while executing inotifywait. This option prevents the messages about the establishment of watches. We may also use –quiet instead of –q.

Now, let’s delete new_file within the /tmp directory and recreate it:

$ rm /tmp/new_file
$ touch /tmp/new_file

As soon as we created the file /tmp/new_file, we observed the following output in the terminal we executed inotifywait:

$ inotifywait –m –q –e create –-format %f /tmp
new_file

The output includes only the file name, as expected.

3.2. Using inotifywait in a Shell Script

Now, we’ll use inotifywait in the script, wait_for_file.sh:

#!/bin/bash

file_to_wait=$1
directory=$(dirname ${file_to_wait})
filename=$(basename ${file_to_wait})
 
while read f
do 
  if [ “$f” = ${filename} ]
  then 
    break
  fi
done < <(inotifywait –m -q -e create –-format %f ${directory})

echo “${file_to_wait} has been created”

This script gets the name of the file that we’ll wait for and assigns it to the variable file_to_wait. The given file name may contain directories, so we use the dirname and basename commands to extract the directory of the file and just the file name. For example, if we pass /tmp/file.txt as the command-line argument to the script, directory will be /tmp, and filename will be file.txt.

As we’ve already seen in the previous section, inotifywait prints the name of the created file. We feed the output of inotifywait to the input of the read command. We use process substitution, <(inotifywait –m –q –e create –-format ‘%f’ ${directory}), to feed the output of inotifywait.

Other files might be created in the watched directory while inotifywait waits for the file passed as the input. So, we use read in a while loop to continue waiting for the input file.

We check whether the file we’re waiting for is created in the conditional expression of the if command within the while loop. If inotifywait detects the creation of the watched file, the conditional expression of the if command becomes true. In this case, we exit from the while loop using the break command.

Finally, the script prints that the file has been created and exits.

Now, let’s run the script in a terminal:

$ rm –f /tmp/new_file
$ wait_for_file.sh /tmp/new_file

We deleted any existing new_file in the /tmp directory before running the script. Now, let’s create a file, /tmp/new_file, in a new terminal using touch:

$ touch /tmp/new_file

As soon as we created the file, the script detected the creation of the file:

$ wait_for_file.sh /tmp/new_file
/tmp/new_file has been created

Therefore, the script detected the creation of the file successfully.

4. Conclusion

In this article, we discussed two different methods to wait for the creation of a file.

First, we checked the existence of the file periodically in a while loop.

Then, we used inotifywait to notify us when the file was created.