Bash

將 subshel l 置於後台與將命令置於後台

  • March 12, 2020

我有兩個 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

腳本 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

由於我檢查的範圍很大,我想並行處理每個 ping 命令。但是,由於資源限制,我的第二個腳本似乎沒有重試失敗的分叉嘗試。這導致第二個腳本的結果不一致,而我的第一個腳本給出了恆定的結果,儘管有時兩者都無法分叉。誰可以給我解釋一下這個?還有是否可以重試失敗的分叉?

已經有一個答案為原始海報問題相關的任務提供了改進的程式碼片段,但它可能還沒有更直接地回答這個問題。

問題是關於差異

  • **A)**直接後台執行“命令”,vs
  • **B)**將一個子shell放入後台(即具有類似的任務)

讓我們檢查執行 2 個測試的那些差異

# A) Backgrounding a command directly
sleep 2 & ps

輸出

[1] 4228
 PID TTY          TIME CMD
4216 pts/8    00:00:00 sh
4228 pts/8    00:00:00 sleep

儘管

# A) backgrounding a subhell (with similar tas)
( sleep 2; ) & ps

輸出類似:

[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

** 測試結果:**

在這個測試(只執行 a sleep 2)中,子shell 版本確實不同,因為它將使用 2 個子程序(即兩個fork()/exec操作和 PID),因此不僅僅是命令的直接後台。

然而script 1,在問題中,命令不是單個命令,sleep 2s而是pipe4 個命令中的一個,如果我們在其他情況下進行測試

  • **C)**使用 4 個命令對管道進行後台處理
# C) Backgrounding a pipe with 4 commands
sleep 2s | sleep 2s | sleep 2s | sleep 2s & ps

產生這個

[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

並表明,在和sscript 1方面確實會是一個更高的應變。PIDs``fork()

作為粗略估計,腳本將使用大約 254 * 4 ~= 1000 個 PID,因此甚至比script 2使用 254 * 2 ~= 500 個 PID 還要多。由於 PID 資源耗盡而發生的任何問題似乎不太可能,因為大多數 Linux 機器

$ cat /proc/sys/kernel/pid_max
32768

為您提供 32 倍所需的 PID,即使案例script 1和所涉及的程序/程序(即sedping等)似乎也不太可能導致不穩定的結果。

正如使用者@derobert 所提到的,scripts失敗背後的真正問題是缺少wait命令,這意味著在循環中的命令後台執行後,腳本結束,因此 shell 導致所有子程序終止。

引用自:https://unix.stackexchange.com/questions/286971