1

I have a while loop in a bash script:

Example:

while read LINE
do
echo $LINE >> $log_file
done < ./sample_file

My question is why when I delete the sample_file while the script is running the loop doesn't end and I see that the log_file is updating? How the loop is continuing while there is no input?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
Mohammad
  • 41
  • 5

3 Answers3

2

In unix, a file isn't truly deleted until the last directory entry for it is removed (e.g. with rm) and the last open file handle for it is closed. See this question (especially MarkR's answer) for more info. In the case of your script, the file is opened as stdin for the while read loop, and until that loop exits (or closes its stdin), rming the file will not actually delete it off disk.

You can see this effect pretty easily if you want. Open three terminal windows. In the first, run the command cat >/tmp/deleteme. In the second, run tail -f /tmp/deleteme. In the third, after running the other two commands, run rm /tmp/deleteme. At this point, the file has been unlinked, but both the cat and tail processes have open file handles for it, so it hasn't actually been deleted. You can prove this by typing into the first terminal window (running cat), and every time your hit return, tail will see the new line added to the file and display it in the second window.

The file will not actually be deleted until you end those two commands (Control-D will end cat, but you need Control-C to kill tail).

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
2

See "Why file is accessible after deleting in unix?" for an excellent explanation of what you are observing here.

In short...

Underlying rm and any other command that may appear to delete a file there is the system call unlink. And it's called unlink, not remove or deletefile or anything similar, because it doesn't remove a file. It removes a link (a.k.a. directory entry) which is an association between a file and a name in a directory.

You can use the function truncate to destroy the actual contents (or shred if you need to be more secure), which would immediately halt the execution of your example loop.

0

The moment shell executes the while loop, the sample_file contents have been read, and it does not matter whether the file exists or not after that point.

Test script:

$ cat test.sh 
#!/bin/bash

while read line
do
    echo $line
    sleep 1
done < data_file

Test file:

$ seq 1 10 > data_file

Now, in one terminal you run the script, in another terminal, you go and delete the file data_file, you would still see the 1 to 10 numbers printed by the script.

Guru
  • 16,456
  • 2
  • 33
  • 46