web-dev-qa-db-ja.com

ローカルファイルを入力パラメータとして受け取るシェルスクリプトのリモート実行

Linux、bash、およびOpenSSHを使用して、少なくとも3つの方法でリモートホスト上でシェルスクリプトを実行できます。

# Method 1: Script is never stored on the remote Host
ssh <username>@<hostname> 'bash -s' < myShellScript

# Method 2: Script is permanently stored on the remote Host
ssh <username>@<hostname> 'myShellScript'

# Method 3: Copy script to the remote Host, execute it, and delete it
scp myShellScript <username>@<hostname>:~
ssh <username>@<hostname> 'myShellScript; rm -f myShellScript'

スクリプトのコピーの急増とそれに関連するメンテナンスの問題を防ぐため、方法2よりも方法1の方が好きです。

スクリプトをコピーして削除するよりも高速で一般的に「クリーン」であるため、方法3よりも方法1の方が好きです。

しかし、メソッド1に固執するという目標を達成するには、回避する必要のある問題があります。myShellScriptは次の形式です。

#!/bin/bash

# Do stuff...
myProgram input myProgramInputFile
# Do more stuff...

ここで、myProgramは、対話する可能性のあるすべてのリモートホストで使用できる標準ユーティリティです。ただし、myProgramInputFileは、ローカルマシンにのみ存在する通常のファイルです。どのリモートホストにも存在しません。

myShellScriptmyProgramInputFileを1つの素敵な「パッケージ」に「バンドル」して、SSH経由でリモートホスト上で明示的に何も保存せずに実行できるようにしたいと思います。永続的または一時的なリモートファイルシステム。これは可能ですか?

3
Dave

少なくともmyProgramInputFileメソッド3 も同様)をコピーしたいと思います。もっと頑強になると思います。ただし、唯一のメソッド1 で機能させる方法があります。



私のアプローチ

適切なファイルをリモート側にコピーし、実行をトリガーし、後でクリーンアップする(ローカル)スクリプトを作成することをお勧めします。

myLocalScript(実行可能)、myRemoteScript、およびmyProgramInputFileの3つのローカルファイルが必要になります。

myLocalScriptの内容:

_#!/bin/bash

# step 1: storing command line arguments to meaningful names
ssh_command="ssh $1"
script="$2"
input="$3"

# step 2: creating remote temporary file
remote_input=$($ssh_command 'mktemp')

# step 3: copying the content of local input file to the remote temporary file
cat "$input" | $ssh_command "cat > \"$remote_input\""

# step 4: sourcing the script to the remote side
$ssh_command "input=\"$remote_input\" bash -s" < "$script"

# step 5: removing the remote temporary file
$ssh_command "rm \"$remote_input\""
_

myRemoteScriptは次のようになります:

_# Shebang is not needed, this script will effectively be sourced

# Do stuff…
myProgram input "$input"
# Do more stuff…
_

ファイルmyProgramInputFile(ローカル)とmyProgram(リモート)は、現在の設定のままになります。

ローカル使用法:

_./myLocalScript <username>@<hostname> myRemoteScript myProgramInputFile
_

テクニカルノートと説明:

  • ステップ2 mktempで、リモートマシンの一時ディレクトリにファイルを作成します。 ステップ2 ステップの間に他の誰かが実際に同じ名前のファイルを作成する状況を回避するために_mktemp -u_を使用したくありません3
  • ステップ3 で、_mktemp -u_を使用した場合、scpを使用できます。リモート一時ファイルはすでに存在するため、catを使用して書き込みます。
  • ステップ4 myRemoteScriptは、リモートマシンコンテキストの一時ファイルへのパスを知る必要があります。そのため、ローカルの_$remote_input_をinput変数としてリモートのbashに渡します。このように、myRemoteScriptが上記のbashに供給されると、その中の_$input_は一時ファイルのパスを示します。
  • リモートを壊した場合bash(たとえば、シングルで Ctrlc)次に、myLocalScriptステップ5 に進み、とにかくクリーニングを実行します。これが、クリーニングがmyRemoteScriptの終わりにない理由ですが、そうなる可能性があります。


唯一の方法1 アプローチ

ヒアドキュメントのおかげで、myProgramInputFilemyShellScriptに埋め込むことができます。

これは簡単ですmyProgramInputFileがテキストファイルで、myProgramstdinを読み取ることができる場合(おそらく_myProgram input -_構文を使用しますか? inputは省略されていますか?)

myShellScriptは次のようになります:

_# Shebang is not needed, this script will effectively be sourced

# Do stuff…

myProgram input - <<"EOF"
The content of myProgramInputFile is pasted here,
it continues here
and here,
and so on.
EOF

# Do more stuff…
_

次に、メソッド1 のように実行します

_ssh <username>@<hostname> 'bash -s' < myShellScript
_

myProgramstdinを読み取れないが、リモートシステムで_/proc/self/_を使用できる場合は、重要な行をmyShellScriptに書き込む必要があります。この:

_myProgram input /proc/self/fd/0 <<"EOF"
_

myProgramInputFileがテキストより大きい場合ローカルでエンコードし(uuencode、_base64_を参照)、リモート側でデコードする必要があります。また、エンコードされたテキストにEOF行がないかどうかを確認する必要があります。ない場合は、ヒアドキュメントの区切り文字を変更してください。 _base64_は___を使用しないため、この場合は_E_O_F_は完全に安全です(ただし、uuencodeでは使用できない可能性があります。わかりません)。


概念実証スーパーユーザーファビコンをgzipで圧縮し、_base64_でエンコードして、スクリプトに埋め込みました。 cpを使用して_/proc/self/fd/0_アプローチを示すことを選択しましたが、_cat > ~/SUfavicon.ico_の場合もあります。パイプの早い段階で_gzip -cd > ~/SUfavicon.ico_以上。

そしてもちろん、あなたの場合、myProgramの代わりにcpがあります。

この場合、_{}_が重要であることに注意してください。これらにより、ヒアドキュメントは_base64 -d_に送信されます。

_# Shebang is not needed, this script will effectively be sourced

{ base64 -d | gzip -cd | cp /proc/self/fd/0 ~/SUfavicon.ico ; } <<"E_O_F"
H4sICE3cXFkCA2Zhdmljb24uaWNvAO2XT2jTUBzHf2lnO1HXIAiKYHuSIYhzoCgIlV1EdtDDTmMg
CIKI7DQ9Taq71Il0VfBSmP9QmKziYRd3GCoqu40JIhtiB7sIOm1AcJ1r8/y+5bXEZ1KbtH07uMCH
3/pLvvm8lzYvC5FGAdJ1Qo3R+RaivUQUi1mfx9BPodeOns77ZPXXthZy25IgX2bbZkrz5uIjmvz+
lPKCBZAEmkOeH8/ABOjXt1AXb86NUg+Ov/AtSwOoy6gl1PYq+UtuA0RuHjCw32d+Dn6znrzwH/SZ
fy78w6gBr3lkOpH9DPg53nrNLzykVpzjDp8DatFLfrCXArkHlBLzfwcOgUANed4zE320/es4fRDz
7/Zw/XiP3TxHm5bGK9f/mJ/rv5StfP++8sjmxLU/7DWP7FHkiqhfUNuq5J+AM7h/jvDm/F06geOv
AJ5bBX0uwyvnTV5x/2bE/fsGmQK8U6hdTsGhsMXItI3XNq5hPQlbVPZjtRiKgKi1zvDV5bh9ndH/
9jDG/iCi6yuAVaOcXczuYy78ALPgOtjhND/Za/OzBvjtfARb19HP6a3Dr5GHDS4NvJL8g3795GOD
77bkv6rYn97w/9f+Ecl/Q7G/X/K/B0GF/t1gRRpDBoRU+MUYLjusgznR39lsvxjDAFh2GMdPFX4x
hrNOzwQF178NPHNwl8BEk39//Bk06eC9BfY06veH/Z1gFNwHKRAW/pMO8+5p9P2H/Wnp+A7hT0ru
qWasP1X88vqbbpL/FJgBs+AF0FX6PTx/Nvzr6x9W7B+T/BdV+fm7BshL/g6F/ozknq7z/Uur0bsL
PJbcv8ABRe9/Jekz///ntNt4m/z+N+M27xr8qz79n8A90M2fv//6vso+I0QJEF8jYcQNVnAjCiIG
KwYNZgIWtP4uhA2zNQriFRzz/NwwJF5yHzNCGgiy3wHSerE2FQAA
E_O_F
_

以前と同じように実行します。

_ssh <username>@<hostname> 'bash -s' < myShellScript
_

次に、リモートマシンに_~/SUfavicon.ico_があります。

2