サブプロセスの標準入力の先頭にデータを注入するには?

サブプロセスの標準入力の先頭にデータを注入するには?

TL; DR cat(クライアントから)がパスワードを求めるsshと競合するときに失敗するこのコマンドラインテンプレートを修正する方法は?

{ echo some stuff; cat; } | ssh SERVER cat
{ echo some stuff; cat; } | ssh SERVER ls

公開/秘密鍵の生成について尋ねるものではありません。リモートコマンドはそのstdinを無視する可能性があるため、stdinを事前に使用したくありません(この場合、ユーザーに^ Dを入力するように強制するのは痛いです)。リモートコマンドが標準入力を読み取るかどうかを示すために、ユーザーはテンプレートにオプションを指定したくありません。リモートコマンドが標準入力を読み取るかどうかにかかわらず、テンプレートが機能したいと思います。


詳細:SSHを介してリモートで実行されるコマンドのクライアントとサーバー側のラッパーを作成したいと思います。問題のコマンドは、ユーザーが選択したコマンドである可能性があります。ラッパーの目的は、コマンド環境を設定することです。クライアントラッパーはサーバー側ラッパーに少量のデータを送信する必要がありますが、そのデータをコマンドラインから送信したくありません(標準入力として送信したい)。

呼び出す方法の例は次のとおりです。

$ wrapper1 HOST wrapper2 sh -c "cat >file"
This data is sent to the remote side
^D

Wrapper1はいくつかのデータを計算し、shを実行する前に環境を設定するWrapper2に渡します。 Catは標準入力から読み込み、リモート側のファイルに書き込みます。

これを達成するために、クライアント側ラッパーがサーバー側ラッパーに送信される標準入力ストリームの先頭にいくつかのデータを挿入したいと思います。サーバー側ラッパーは、実際のコマンドを実行する前に stdin で追加データを使用します。

注入されたデータを送信して消費した後、リモートコマンドの標準入力パイプがこのデータ注入のないものと等しくなることを望みます。リモートコマンドは、標準入力から何も読み取ることも、読み取らない場合もあります。これは実行中の特定のコマンドによって異なります。

どのコマンドが実行されているのか、および標準入力から読み取るべき項目があるかどうかは事前にわからないため、クライアントはリモートコマンドを呼び出す前に標準入力全体を消費したくありません。

私がやろうとしていることの詳細は次のとおりです。

CMDがあらかじめ知られていない「ssh HOSTwrapper2CMD」の周りにWrapper1を作成したいと思います(ttyは必要ありませんが、stdinを読んでも読まないかもしれません)。 Wrapper2 が CMD を実行する前に、Wrapper1 は Wrapper2 が読み取れるように、いくつかの追加データをリモートの端に送信します。私はラッパー1がある程度透明になりたいです。追加データを送信してCMDを実行する前に、追加データを読み取るためにリモートコマンドでラッパー2を実行することを除いて、sshのように機能する必要があります。リモートCMDがstdinを読み取る場合は、「ssh HOST CMD」を実行しているかのように、ラッパー1のstdinコンテンツを取得したいと思います。

私はラッパー1にstdoutに追加のデータを書き込む子プロセスを作成させ、次にcatを実行してstdinをstdoutにコピーするようにしてこのコードを書きました。 Wrapper1 は、子プロセスの出力を ssh コマンドの標準入力にパイプします。ただし、catとsshの両方がキーボード入力のために競合しているため(CMDがインタラクティブに実行されている場合)、sshにパスワードの入力を求められた場合、この方法は失敗します。子供の猫の前に睡眠を挿入すると機能しますが、明らかに最適ではありません。

CMDがstdinを読んでいるかどうかわからないので、競合を避けるためにsshを実行する前にすべてのstdinを使用することはできません。それにもかかわらず、すべてのstdinを読むことは、多くのシナリオ(例えば、非常に大きい、または増分消費が必要な場合)で最適です。

私が望むことをする方法はありますか?今私が考えることができるのは、次の選択肢を提供するWrapper1のオプションだけです。

  1. 標準入力全体を消費してリモートエンドに送信するか、
  2. /dev/null から標準入力をリダイレクトします。

ただし、ユーザーにこれら2つのオプションのいずれかを選択するように要求することなく、通常はラッパーなしでstdinからデータを徐々に読み取ることを許可することをお勧めします。

答え1

したがって、次のように常にファイルをSTDINにリダイレクトするようにCMDを設定できます。

cmd < file.txt

または、最初にファイルを読み取り、整理してから文字列として送信することもできます。

cmd <<< "string"

その後、CMDスクリプトを呼び出すときに./wrapper2を呼び出す前に、パラメータをそのままファイルに挿入できます。 STDINが不要な場合は、実行後に一時ファイルを自動的に削除または切り捨てて誤った内容を転送しないようにしてください。

答え2

質問を正しく理解したかどうかはわかりません。

wrapper1 () {
    host="$1"
    shift
    {
         echo "nonsensical statement involving wrapper2"
         cat
    } | ssh $host wrapper2 "$@"
}

バッファリングに注意してください。

関連情報