Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Waiting for a file to be created in Bash

Tags:

bash

unix

I need to create a bash script to wait for a file to be created. The script will use sleep command inside a while loop to periodically check on a file every 10 seconds. Print out a message while waiting. Display the content of the file once the file is created. Below is what I have tried to implement and it obviously does not work. At this point, I'm not entirely sure how to proceed.

#!/bin/bash
let file=$1

while '( -f !  /tmp/$1)'
do
       sleep 10
       echo "still waiting"
done

echo "Content of the file $1:"
like image 767
J.Clark Avatar asked Oct 14 '16 16:10

J.Clark


People also ask

How do I wait for a file in shell script?

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.

Is there a wait function in bash?

The bash wait command is a Shell command that waits for background running processes to complete and returns the exit status. Unlike the sleep command, which waits for a specified time, the wait command waits for all or specific background tasks to finish.

How do you wait time in bash?

How to Use the Bash Sleep Command. Sleep is a very versatile command with a very simple syntax. It is as easy as typing sleep N . This will pause your script for N seconds, with N being either a positive integer or a floating point number.

How do you use the wait command?

wait command will suspend execution of the calling thread until one of its children terminate. It will return the exit status of that command. The sleep command is used to delay the execution of the next command for a given number of seconds, hours, minutes, days. kill is used to terminate a background running process.


1 Answers

The problem here is with the test, not the sleep (as the original question hypothesized). The smallest possible fix might look as follows:

while ! test -f "/tmp/$1"; do
  sleep 10
  echo "Still waiting"
done

Keep in mind the syntax for a while loop:

while: while COMMANDS; do COMMANDS; done
    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.

That is to say, the first argument given to while, expanding the loop, is a command; it needs to follow the same syntax rules as any other shell command.

-f is valid as an argument to test -- a command which is also accessible under the name [, requiring a ] as the last argument when used in that name -- but it's not valid as a command in and of itself -- and when passed as part of a string, it's not even a shell word that could be parsed as an individual command name or argument.

When you run '( -f ! /tmp/$1)' as a command, inside quotes, the shell is looking for an actual command with exactly that name (including spaces). You probably don't have a file named '/usr/bin/( -f ! /tmp/$1)' in your PATH or any other command by that name found, so it'll always fail -- exiting the while loop immediately.


By the way -- if you're willing to make your code OS-specific, there are approaches other than using sleep to wait for a file to exist. Consider, for instance, inotifywait, from the inotify-tools package:

while ! test -f "/tmp/$1"; do
  echo "waiting for a change to the contents of /tmp" >&2
  inotifywait --timeout 10 --event create /tmp >/dev/null || {
    (( $? == 2 )) && continue  ## inotify exit status 2 means timeout expired
    echo "unable to sleep with inotifywait; doing unconditional 10-second loop" >&2
    sleep 10
  }
done

The benefit of an inotify-based interface is that it returns immediately upon a filesystem change, and doesn't incur polling overhead (which can be particularly significant if it prevents a system from sleeping).


By the way, some practice notes:

  • Quoting expansions in filenames (ie. "/tmp/$1") prevents names with spaces or wildcards from being expanded into multiple distinct arguments.
  • Using >&2 on echo commands meant to log for human consumption keeps stderr available for programmatic consumption
  • let is used for math, not general-purpose assignments. If you want to use "$file", nothing wrong with that -- but the assignment should just be file=$1, with no preceding let.
like image 162
Charles Duffy Avatar answered Oct 05 '22 03:10

Charles Duffy