0

My requirement is to replace file only when it is not being accessed. I have following snippet:

if [ -f file ]
then
    while true
    do
       if [ -n "$(fuser "file")" ]
       then
           echo "file is in use..."
       else
           echo "file is free..."
           break
       fi
   done
fi

{
   flock -x 3
   mv newfile file
} 3>file

But I have a doubt that I am not handling concurrency properly. Please give some insights and possible way to achieve this.

Thanks.

user1228352
  • 569
  • 6
  • 21

2 Answers2

1

My requirement is to replace file only when it is not being accessed.

Getting requirements right can be hard. In case your actual requirement is the following, you can boil down the whole script to just one command. My guess on the actual requirement (not as strict as the original):

Replace file without disturbing any programs reading/writing file.

If this is the case, you can use a very neat behavior: In Unix-like systems file descriptors always point to the file (not path) for which they where opened. You can move or even delete the corresponding path. See also How do the UNIX commands mv and rm work with open files?.

Example:

Open a terminal and enter

i=1; while true; do echo $((i++)); sleep 1; done > file &
tail -f file

The first command writes output to file and runs in the background. The second command reads the file and continues to print its changing content.

Open another terminal and move or delete file, for instance with

mv file file2
echo overwritten > otherFile
mv otherFile file2
rm file2
echo overwritten > file
echo overwritten > file2

While executing these commands have a look at the output of tail -f in the first terminal – it won't be affected by any of these commands. You will never see overwritten.

Solution For New Requirement:

Because of this behavior you can replace the whole script with just one mv command:

mv newfile file
Socowi
  • 25,550
  • 3
  • 32
  • 54
0

Consider lsof.

mvWhenClear() {
  while [[ -f "$1" ]] && lsof "$1"
  do sleep $delay
  done
  mv "$1" "$2" # still allows race condition
}
Paul Hodges
  • 13,382
  • 1
  • 17
  • 36