为什么这个inotifywait shellscript会出现两个PID?

时间:2015-06-05 15:45:34

标签: linux bash unix inotifywait

我正在学习使用inotifywait,特别是使用以下脚本:https://unix.stackexchange.com/questions/24952/script-to-monitor-folder-for-new-files。我不明白的是,当我使用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

为了更快地进行测试,我更改了链接脚本,以便您可以通过$ 1传递任何文件夹以进行观察,并保存为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

为什么脚本进程会出现两次?在这个过程的某个地方有叉子吗?有人可以解释为什么这两个过程的行为正好发生了吗?

1 个答案:

答案 0 :(得分:4)

因为它有一个管道。

管道分支子shell - 第二个进程 - 并连接它们。在foo | bar的情况下 - 那些是外部的,非shell命令 - 子shell exec实际命令,因此丢失了它们的进程树条目。当该管道的一个元素写在shell中时,执行它的shell仍保留在进程树中。

那就是说,我建议 [1] 写一点不同:

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)

这会将while循环保留在主进程中,而exec会使分叉的子shell替换为inotifywait。因此,您在while循环内所做的更改(例如在脚本中设置变量)将在脚本从循环移动后保留,而如果您将循环放在管道中,则任何变量都会设置在它的范围是子shell。有关详细信息,请参阅BashFAQ #24

[1] - 实际上,如果你想彻底涵盖所有的角落案例,我建议你写一个与此不同的内容。由于POSIX文件名可以包含除NUL之外的任何字符或/(当然,/可以存在于路径名中),因此空格或换行名称是一个非常糟糕的主意;在以空格结尾的名称周围的现有实现中也存在错误。不幸的是,由于inotifywait不允许自定义格式字符串包含\0到NUL分隔它们,因此从它获得完全明确的输出是非常棘手的; StackOverflow上的其他答案已经涵盖了它,我不太倾向于在这里重现它们的内容。