Myk*_*III 10 bash shell-script fork subshell
我有两个 bash 脚本尝试检查已启动的主机:
脚本 1:
#!/bin/bash
for ip in {1..254}; do
ping -c 1 192.168.1.$ip | grep "bytes from" | cut -d" " -f 4 | cut -d ":" -f 1 &
done
Run Code Online (Sandbox Code Playgroud)
脚本2:
#!/bin/bash
for ip in {1..254}; do
host=192.168.1.$ip
(ping -c 1 $host > /dev/null
if [ "$?" = 0 ]
then
echo $host
fi) &
done
Run Code Online (Sandbox Code Playgroud)
当我检查大范围时,我想并行处理每个 ping 命令。但是,由于资源限制,我的第二个脚本似乎没有重试失败的分叉尝试。这导致第二个脚本的结果不一致,而我的第一个脚本尽管有时都无法分叉,但仍给出了恒定的结果。谁可以给我解释一下这个?还有无论如何要重试失败的分叉吗?
已经有一个答案,它为原始海报问题相关的任务提供了改进的代码片段,而它可能还没有更直接地回答问题。
问题是关于差异的
让我们检查运行 2 个测试的那些差异
# A) Backgrounding a command directly
sleep 2 & ps
Run Code Online (Sandbox Code Playgroud)
产出
[1] 4228
PID TTY TIME CMD
4216 pts/8 00:00:00 sh
4228 pts/8 00:00:00 sleep
Run Code Online (Sandbox Code Playgroud)
尽管
# A) backgrounding a subhell (with similar tas)
( sleep 2; ) & ps
Run Code Online (Sandbox Code Playgroud)
输出类似:
[1] 3252
PID TTY TIME CMD
3216 pts/8 00:00:00 sh
3252 pts/8 00:00:00 sh
3253 pts/8 00:00:00 ps
3254 pts/8 00:00:00 sleep
Run Code Online (Sandbox Code Playgroud)
** 检测结果:**
在这个测试(只运行 a sleep 2)中,子shell 版本确实不同,因为它将使用 2 个子进程(即两个fork()/exec操作和 PID),因此不仅仅是命令的直接后台处理。
在script 1的问题然而,命令是不是一个单一的sleep 2s,而是它是一个pipe4个的命令,其中,如果我们在另外的情况下,测试
# C) Backgrounding a pipe with 4 commands
sleep 2s | sleep 2s | sleep 2s | sleep 2s & ps
Run Code Online (Sandbox Code Playgroud)
产生这个
[2] 3265
PID TTY TIME CMD
3216 pts/8 00:00:00 bash
3262 pts/8 00:00:00 sleep
3263 pts/8 00:00:00 sleep
3264 pts/8 00:00:00 sleep
3265 pts/8 00:00:00 sleep
3266 pts/8 00:00:00 ps
Run Code Online (Sandbox Code Playgroud)
并表明实际上s和sscript 1将是一个更高的应变。PIDsfork()
作为粗略估计,脚本将使用大约 254 * 4 ~= 1000 个 PID,因此甚至超过script 2254 * 2 ~= 500 个 PID。由于 PID 资源耗尽而发生的任何问题似乎不太可能,因为大多数 Linux 机器
$ cat /proc/sys/kernel/pid_max
32768
Run Code Online (Sandbox Code Playgroud)
给你32个倍甚至必要的情况下的PIDscript 1和进程/参与计划(即sed,ping等)似乎也不太可能导致不定结果。
正如用户@derobert 所提到的,scripts失败背后的真正问题是wait命令丢失,这意味着在循环中后台运行命令后,脚本结束,因此 shell 导致所有子进程终止。