Search code examples
perlfile-exists

Are there any pitfalls to testing for file existence in a while conditional?


I recently came across an interesting line of code that waits until a particular file springs to life:

sleep 1 until -e $file;

While at face value the line does what one expects it to, I can't but help feel that something is not right here; it just seems more natural to write the following:

while (1) {

    sleep 1;
    last if -e $file;
}

Are the file test operators intended for use only with if and unless? And are there any performance penalties in deploying such operators within while conditionals?


Solution

  • There is no difference between using a file test operator in a while-true (while) vs a while-false (until) loop, or by separating out the test with an if/unless, nor is there a difference with anything else in Perl.

    The only magical case with the while loop is ... while <$handle>; or while (<$handle>) {...} which sets $_ to the next line while it is defined. And it doesn't really make sense to use the while-false (until) loop with bare handles.

    The a until b construct is simply a while not b.

    To convert sleep 1 until -e $file; into a while loop, you would use the following:

    sleep 1 while not -e $file;
    

    This can then be expanded to the block form:

    while (not -e $file) {sleep 1}
    

    Or as an infinite while with internal escape:

    while (1) {
       last if -e $file;
       sleep 1;
    }
    

    And all of these forms are equivalent.

    Answering the rest of your question, most file systems should be fine with 1 second sleeps between checks, but you many way to pick a larger number if the process is not urgently waiting on the file. Also if you are on a device with a slow file system (stored in flash memory or via slow network) you might want to experiment with larger values as well.

    And as ysth nitpicks below, in general, statement forms return differently than block forms when they are the last element of a construct that returns: do {...}, sub {...}, do FILE, eval ...