为啥这个 inotifywait shellscript 使用两个 PID?

Posted

技术标签:

【中文标题】为啥这个 inotifywait shellscript 使用两个 PID?【英文标题】:Why does this inotifywait shellscript shop up with two PIDs?为什么这个 inotifywait shellscript 使用两个 PID? 【发布时间】:2015-06-05 15:45:33 【问题描述】:

我正在学习使用 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】:

因为它有一个管道。

管道会派生出一个子外壳——第二个进程——并将它们连接起来。对于foo | bar——它们都是外部的非shell命令——子shellsexec是实际的命令,因此会丢失它们的进程树条目。当该管道的元素写入 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 分隔,因此从中获得完全明确的输出非常棘手;它已在 *** 上的其他答案中有所介绍,我不太愿意在这里复制它们的内容。

【讨论】:

以上是关于为啥这个 inotifywait shellscript 使用两个 PID?的主要内容,如果未能解决你的问题,请参考以下文章

inotify为啥无法检视共享文件夹

inotifywait命令

如何连续运行 inotifywait 并将其作为 cron 或守护进程运行?

在运行脚本之前使用 inotifywait (或替代方法)等待 rsync 传输完成?

抑制或防止重复的 inotifywait 事件?

利用inotifywait监控主机文件和目录