web-dev-qa-db-ja.com

サブシェルをバックグラウンドに配置するか、コマンドをバックグラウンドに配置するか

稼働中のホストをチェックしようとする2つの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コマンドを並行して処理したいと思います。ただし、2番目のスクリプトは、リソースの制限により、失敗したフォークの試行を再試行しないようです。これにより、2番目のスクリプトの結果に一貫性がなくなりますが、最初のスクリプトでは、フォークが両方とも失敗したにもかかわらず、一定の結果が得られます。誰かがこれを私に説明できますか?また、失敗したフォークを再試行する方法はありますか?

7
MykelXIII

元の投稿者の質問が関連していたタスクに改善されたコードスニペットを提供する回答がすでにありますが、質問への直接の回答はまだない可能性があります。

問題は、

  • A)「コマンド」を直接バックグラウンド化する、vs
  • B)サブシェルをバックグラウンドに配置(つまり、同様のタスクを使用)

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
_

** 試験結果:**

このテスト(_sleep 2_のみを実行)では、2つの子プロセス(つまり、2つのfork()/exec操作とPID)を使用するため、サブシェルバ​​ージョンは実際に異なります。コマンドの直接のバックグラウンド以上のものです。

質問の_script 1_では、コマンドは単一の_sleep 2s_ではなく、代わりに4つのコマンドのpipeでした。追加のケースでテストすると、

  • 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
_

そして、実際に_script 1_はPIDsおよびfork() sの点ではるかに高いひずみになることを示しています。

おおまかな見積もりとして、スクリプトでは約254 * 4〜= 1000 PIDを使用し、したがって254 * 2〜= 500 PIDの_script 2_よりも多く使用します。ほとんどのLinuxボックス以降、PIDリソースの枯渇が原因で発生する問題はまだありそうにありません

_$ cat /proc/sys/kernel/pid_max
32768
_

_script 1_の場合でも必要なPIDの32倍を提供し、関連するプロセス/プログラム(つまりsedpingなど)も結果が一定しない可能性は低いようです。

ユーザー@derobertが述べたように、scriptsの失敗の背後にある実際の問題は、waitコマンドの欠落でした。つまり、ループ内のコマンドをバックグラウンドにした後、スクリプトの終わり、つまりシェルにより、すべての子プロセスが終了しました。

4

これはあなたが期待していることをします:

#!/bin/bash
function_ping(){
    if ping -c 1 -w 5 $1 &>/dev/null; then 
        echo "UP: $1"
    else
        echo "DOWN $1" 
    fi
}
for ip in {1..254}; do
        function_ping 192.168.1.$ip &  
done
wait 

並列処理として保存し、実行します。

それはあなたを助けますか?これは大きな関数に変換でき、高速whileループでも使用できるため、想像力プログラミングを使用できます。

注:bashを使用する必要があります。