複数のリモートサーバーで実行するローカルスクリプトがあります。私が使用しているコマンド構文は次のとおりです。
ssh <remote_server> "bash -s" < ./local_script.sh
これは正常に動作し、パラメーターをlocal_script.shに渡すこともできます。ただし、次のように入力ファイルを渡したいのですが。
local_script.sh < local_file.txt
これら2つのステートメントを組み合わせると、次のようになります。
ssh <remote_server> "bash -s" < ./local_script.sh < local_file.txt
これを実行すると、
bash: line 1: FOO: command not found
bash: line 2: BAR: command not found
bash: line 3: BAZ: command not found
...
ここで、FOO、BAR、BAZなどはlocal_file.txtの各行の最初のWordです。
FOO FOO_PARAM1
BAR BAR_PARAM1
BAZ BAZ_PARAM2
...
したがって、"bash -s"
リモートサーバー上のlocal_script.shへの入力ファイルではなく、スクリプトファイルとしてlocal_file.txtを解釈しています。これを修正する方法はありますか(ラッパースクリプトを作成する以外)?
ssh
は2つの個別の出力ストリーム(stdoutとstderr)を提供しますが、1つの入力ストリーム(stdin)のみを供給します。したがって、さまざまなメカニズムを介してスクリプトのコンテンツと入力ファイルを渡す必要があります。
たとえば、1つは変数を使用し、もう1つはstdinを使用します。
LC_CODE=$(cat local_script.sh) ssh Host 'eval "$LC_CODE"' < input
(両方のssh
クライアントがLC_*
変数(SendEnv
in ssh_config
)とsshd
サーバーはそれらを受け入れます(AcceptEnv
in sshd_config
))
または、単にlocal_script.sh
は、リモートユーザーのログインシェルがそのスクリプトの構文に適したものであると想定したリモートシェルコードです。
ssh Host "$(cat local_script.sh)" < input
または、次のようにコードとssh
の標準入力に供給される入力を連結します。
{
echo '{'; cat local_script.sh; echo '}; exit'
cat input
} | ssh Host 'bash -s some arguments'
ここではbash
を使用しています。これは、bash
が一度に1バイトずつ入力を読み取って、それを超えて読み取らないようにするためです}; exit
行。他のすべてのシェルがそうするわけではありません。
または、リモートホストのsed
がGNU sed
の場合:
echo '#END-OF-SCRIPT' | cat local_script.sh - input |
ssh Host 'set some arguments; eval "$(sed -u "/^#END-OF-SCRIPT/q")"'
(ここでは、リモートユーザーのログインシェルによってコードが評価され、ボーンに似ていると想定しています)
これはうまく機能し、複数のファイルの内容をスクリプトに渡すこともできます。
ssh Host "bash -s -- '$(cat local_file_1.txt)' '$(cat local_file_2.txt)'" < local_script.sh
説明は、ssh
はログイン時にbash -s
を実行し、スクリプトの引数は--
の後に続くすべてになるということです。したがって、$1
はlocal_file_1.txt
のコンテンツになり、$2
はlocal_file_2.txt
のコンテンツになります。 bash -s
は、< local_script.sh
から取得したstdinからコマンドを読み取ります。