2011-07-06 9 views
4

私が書いているbash関数では、ssh経由で複数のリモートコマンドを開始し、別々のバックグラウンドプロセスで実行させます。これらのプロセスのそれぞれは、多くの行のテキストを生成し、それらを併合してソートします。私の問題は、これらの行が混在することがあることです。つまり、1行が印刷を開始し、その行が印刷を終了する前に、別の行が同じ行に印刷を開始します。bashスクリプトで複数のバックグラウンドプロセスの行をアトミックに印刷する方法は?

私の質問は、個々の行が混ざり合わないように、このプリント出力をアトミックにする最も簡単な方法は何ですか(全行が散在していてもいいですか?私が持っていた1つのアイデアは、各並列バックグラウンドプロセスの出力を保存し、それをシリアルにマージすることでしたが、これを動作させることができませんでした(このメソッドは正しく動作する方法を知っていればうまく動作するはずです)。参考のために、ここで私が書くしようとしているスクリプトの種類の概要である:

foo() { 
    (
     pids=() 
     for x in "[email protected]" 
     do 
      (
       ssh $x 'some-high-latency-command-with-200-lines-of-data-output' 
      ) & 
      pids+=($!) 
     done 
     for x in "${pids[@]}" 
     do 
      wait $x 
     done 
    ) 2> /dev/null 
} 

答えて

3

私は、独自のファイルに各ssh実行をリダイレクトし、その後、それらをマージします。私もループwaitを使用しませんでした。 waitは、すべてのバックグラウンドプロセスを待つか、実際にはsshプロセスだけが必要な場合はwait ${pids[*]}と言うことができます。

+0

おかげで、待機のためにその構文は、物事ビットを簡素化しますが、基本的と同じことを行いよりコンパクトな表記でループします。しかし、ファイルを作成せずにこれを行うといいですね。 – jonderry

+0

しかし、シェルは本当にそのようなことをすることはできません。あなたはバックグラウンド 'ssh'をバックグラウンド' sshとすることができます... |一方、読書l。 do "$ l" >>ファイルをエコーし​​ます。ブロックされていない出力またはブロックバッファされた出力の代わりにラインバッファリングを実行することを唯一の目的とする無償のループのためにかなり遅くなる。後でデータを使って何をやっているかによって、後になるまでマージステップをオフにすることは、厄介な 'ssh'からシェルスクリプトへのパイプラインよりも優れており、信頼性が高くなります。 – geekosaur

+0

私は実際に出力を 'less'にパイプし、'& 'で行のサブセットを選択して、マシン間のさまざまな統計を比較しています。私はデータを永続的に保持する必要はありません。これらは比較的短時間の実験で、8-10台までのマシンを並行して約10秒しかかかりません。しかし、私はこれらのテストを頻繁に実行しているため、個々の出力を手動で比較するのではなく、スクリプトの利点があります。 – jonderry

2

最後に、ファイルを作成せずに動作するように見えるソリューションに遭遇しました。どうやら、sshの出力をdeclareという変数に代入すれば、その行は保存され、echoを使ってこの変数から出力すると、アトミックに見えます。以下を参照してください。

foo() { 
    (
     pids=() 
     for x in "[email protected]" 
     do 
      (
       declare output=$(ssh $x 'some-command-with-multiline-output') 
       echo "$output" 
      ) & 
      pids+=($!) 
     done 
     wait ${pids[*]} 
    ) 2> /dev/null 
} 
1

は、例えば、それらを印刷する前に、ローカルラインを再構成するために、いくつかのプログラムを使用します。

ssh $x 'some-high-latency-command-with-200-lines-of-data-output' | perl -pe1 
関連する問題