为什么这个 inotifywait shellscript 使用两个 PID?
Why does this inotifywait shellscript shop up with two PIDs?
我正在学习使用 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 -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
为什么脚本进程出现两次?这个过程中有分叉吗?有人可以解释为什么会发生两个进程的这种行为吗?
因为它有管道。
管道分叉子shell——第二个进程——并连接它们。在 foo | bar
的情况下——它们都是外部的、非 shell 命令——subshells 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 "" -e create -e moved_to)
这将在主进程中保留 while 循环,并且 exec
使分叉子 shell 替换为 inotifywait
。因此,您在 while
循环内所做的更改——例如在脚本中设置变量——即使在脚本离开循环后仍然存在,而如果您将循环放在管道中,则在它的范围是 subshell。有关详细信息,请参阅 BashFAQ #24。
[1] - 实际上,如果您想彻底涵盖所有极端情况,我建议您写得比这更不同。由于 POSIX 文件名可以包含 NUL 或 /
以外的任何字符(当然 /
可以存在于路径名中),space- 或换行符分隔名称是非常糟糕的主意;在以白色 space 结尾的名称周围的现有实现中也存在错误。不幸的是,由于 inotifywait
不允许自定义格式字符串包含 [=19=]
以 NUL 分隔它们,因此从中获得完全明确的输出非常棘手; Whosebug 上的其他答案已经涵盖了它,我不太愿意在这里复制它们的内容。
我正在学习使用 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 -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
为什么脚本进程出现两次?这个过程中有分叉吗?有人可以解释为什么会发生两个进程的这种行为吗?
因为它有管道。
管道分叉子shell——第二个进程——并连接它们。在 foo | bar
的情况下——它们都是外部的、非 shell 命令——subshells 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 "" -e create -e moved_to)
这将在主进程中保留 while 循环,并且 exec
使分叉子 shell 替换为 inotifywait
。因此,您在 while
循环内所做的更改——例如在脚本中设置变量——即使在脚本离开循环后仍然存在,而如果您将循环放在管道中,则在它的范围是 subshell。有关详细信息,请参阅 BashFAQ #24。
[1] - 实际上,如果您想彻底涵盖所有极端情况,我建议您写得比这更不同。由于 POSIX 文件名可以包含 NUL 或 /
以外的任何字符(当然 /
可以存在于路径名中),space- 或换行符分隔名称是非常糟糕的主意;在以白色 space 结尾的名称周围的现有实现中也存在错误。不幸的是,由于 inotifywait
不允许自定义格式字符串包含 [=19=]
以 NUL 分隔它们,因此从中获得完全明确的输出非常棘手; Whosebug 上的其他答案已经涵盖了它,我不太愿意在这里复制它们的内容。