サブシェルの背景化とコマンドの背景化の比較

サブシェルの背景化とコマンドの背景化の比較

ホストが動作していることを確認する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番目のスクリプトでは一貫性のない結果が発生しますが、最初のスクリプトは一貫した結果を提供しますが、どちらもブランチに失敗することがあります。誰でも私にこれを説明できますか?失敗したフォークを再試行する方法もありますか?

答え1

もともとポスターの質問に関連するタスクに改善されたコードスニペットを提供する答えはすでにありますが、まだ質問に直接答えることができない可能性があります。

質問は違いについてです。

  • ㅏ)バックグラウンドで直接「コマンド」を実行するのと比較
  • 2)サブシェルをバックグラウンドに配置します(たとえば、同様の操作を実行します)。

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

**テスト結果:**

このテスト(のみ実行)では、サブシェルバ​​ージョンは2つのサブプロセス(2つの/タスクとPIDなど)をsleep 2使用するため、コマンドをバックグラウンドで直接実行する以上のものがあるという点で違いがあります。fork()exec

ただし、質問では、script 1コマンドは単一のコマンドではなく4つのコマンドですsleep 2spipe別のケースでテストすると

  • 氏)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、sの観点から見ると、実際にはより高い変形になることを示しています。PIDsfork()

おおよその推定では、スクリプトは約254 * 4〜= 1000 PIDを使用するため、script 2254 * 2〜= 500 PIDよりも多くなります。 PIDリソースの枯渇による問題は、ほとんどのLinuxシステムのようにほとんど発生しません。

$ cat /proc/sys/kernel/pid_max
32768

必要なPIDの32倍を提供すると、関連script 1するプロセス/プログラム(sedなどping)が不安定な結果につながる可能性はほとんどありません。

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

答え2

これにより、期待どおりに達成されます。

#!/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を使用する必要があります。

関連情報