I am learning to use inotifywait, specifically by using the script at: https://unix.stackexchange.com/questions/24952/script-to-monitor-folder-for-new-files. What I do not understand is why my scripts always appear two times when I use pid x
.
36285 pts/1 S+ 0:00 /bin/bash ./observe2.sh /home/user1/testfolder
36286 pts/1 S+ 0:00 inotifywait -m /home/user1/testfolder -e create -e moved_to
36287 pts/1 S+ 0:00 /bin/bash ./observe2.sh /home/user1/testfolder
For quicker testing, I changed the linked script so that you can pass any folder via $1 to be observed, and saved as observe2.sh
:
#!/bin/bash
inotifywait -m $1 -e create -e moved_to |
while read path action file; do
echo "The file '$file' appeared in directory '$path' via '$action'"
# do something with the file
done
Why does the script process show up two times? Is there a fork somewhere in the process? Could somebody explain why exactly this behavior of two processes is happening?
Because it has a pipeline.
A pipeline forks a subshell -- a second process -- and connects them. In the case of foo | bar
-- where those are both external, non-shell commands -- the subshells exec
the actual commands, and thus lose their process tree entries. When an element of that pipeline is written in shell, a shell to execute it remains in the process tree.
That said, I'd suggest[1] writing it a bit differently:
while read -r path action file; do
echo "The file '$file' appeared in directory '$path' via '$action'"
# do something with the file
done < <(exec inotifywait -m "$1" -e create -e moved_to)
This will keep the while loop in the main process, and the exec
makes the forked-off subshell replace itself with inotifywait
. Thus, changes you make inside the while
loop -- such as setting variables in your script -- will persist even after the script moves on from the loop, whereas if you put the loop in a pipeline, any variables set in it are scoped to the subshell. See BashFAQ #24 for details.
[1] - Actually, I'd suggest writing it even more differently than that, if you want to cover all the corner cases thoroughly. Since POSIX filenames can contain any character other than NUL or /
(and /
can, of course, exist in pathnames), space- or newline-separating names is a very bad idea; there are also bugs in the existing implementation around names that end in whitespace. Unfortunately, since inotifywait
doesn't allow custom format strings to contain \0
to NUL-delimit them, getting completely unambiguous output from it is quite tricky; it's been covered in other answers on StackOverflow, and I'm not much inclined to reproduce their contents here.