パイプラインでのデータ喪失の現象に暫定対処する(シェルスクリプト)

課題

パイプラインの中で別のマシンへログインする操作を含む場合、パイプラインを流れているはずのデータが喪失する。

例えば以下のようなスクリプトを考える。 これを実行すると標準出力には1から10までの数値が出力されることが想定される。

seq 1 10 | while read -r d
do
    echo $d
    ssh $user@$host echo hello
done

しかし、実行結果は以下のようになった。

1

解決策

「課題」に記載の通り、悪さをしているのが「他のマシンへログインすること」であることは明白だ。 ただし具体的にどのような動作が行われているのかは筆者にはわからない(詳細についてご存知の方はこっそり教えてください…(:3 」∠ )

しかし、原因が完璧にわからなくとも、暫定の対処は可能だ。 ヒントは以下の記事にある。 つまり「他のマシンへログインする」ためのシェル実行環境を隔離してしまえばよい。

副作用の影響を局所化する

ただしログインすることがプロセス全体に対して影響を及ぼす可能性を考慮して、サブシェルではなくバックグラウンドプロセスとして本体から切り離して実行することとする。 このとき一つだけ注意するべきは、バックグラウンドプロセスとして切り離すと処理が独立してしまい、もとのプロセスと同期されないことだ。 なので、もとのプロセスでwaitコマンドを忘れずに入れて、処理を同期するようにする。


上記の内容を反映すると、「課題」で例示したスクリプトは以下のように書き換えられる。 これを実行すると、標準出力には期待通り1から10までの数値が出力される。

seq 1 10 | while read -r d
do
    echo $d
    (
      ssh $user@$host echo hello
    )  &
    wait
done

所感

これは最近業務において実際に筆者が遭遇した問題を題材にしている。 様々なサーバへログインしてコマンドを実行する・ファイルをコピーするスクリプトを含めたところ、課題にあるような状況が発生して恐怖した。 詳細な調査に時間をかけることができないため暫定対応を行った。

本番環境でないときにこのような状況に遭遇して現象を認識できたことは運が良かったと考えたい。