SSH経由でネストされたローカルbash機能を実行する

SSH経由でネストされたローカルbash機能を実行する

他の関数などを使用する複数の関数を宣言するこのようなスクリプトがあります。

#!/bin/bash

function a {
    ...
}

function b {
    ...
    a
    ...
}

...

別のスクリプトはこのスクリプトの一部の機能を使用します。

#!/bin/bash

do_something

source "/path/to/functional/script"

ssh user@host "$(typeset -f f_from_that_script); f_from_that_script"
...

それが言う問題は、environment: line N: another_f_from_that_script: command not found最初の関数が2番目の関数を内部的に使用することを意味します。

function f_from_that_script {
    ...
    another_f_from_that_script
    ...
}

SSHを介して実行できるように、これらすべての機能を定義する方法はありますか?

答え1

いいえ、bashのパーサーはこれらの詳細な構文解析は不可能です(呼び出した関数の名前を実行時に計算できるため、しばしば不可能です)。私が知る限り、これを行うことができるサードパーティパーサーはありませんが、すべての場合にこれが理論的に不可能な理由を説明する論文があります。私は書いた回答それについて。

個々の機能を渡すのではなく、すべての機能を含む完全なスクリプトを実行することをお勧めします。 scpを介してスクリプトを一時的な場所にコピーし、sshを介してコピーするか、sourcesshを介してスクリプト全体をstdinにパイプすることでこれを実行できます。

定期的にSSHを介して複雑な機能を実行する必要がある場合は、SSHなどのより強力で正式なリモート管理ツールを使用できますansible

答え2

あなたはいつも合格できますみんなリモートシェルの既知の機能定義:

#! /bin/bash -

do_something

source "/path/to/functional/script" || exit

{
  typeset -f # output all function definitions
  echo f_from_that_script
} | ssh user@host bash

sshdonは、渡されたコマンドを解釈するためにログインシェルを実行することhostに注意してください。これは必ずしもbashである必要はありません(最近、誰がこれをログインシェルとして使用しますか?)。userbash

また、bash構文は次のように異なります。

  • ロケール(特にLC_CTYPEカテゴリ:文字セットと文字クラス)
  • extglob有効なオプションセット(例:)
  • バッシュバージョン

したがって、bashロケールとバージョンがローカルホストとリモートホストの間で異なる場合、またはデフォルトオプションを変更する場合は、潜在的な問題に注意してください。

答え3

以下を使用して関数を手動でロードできます。

. /path/to/functional/script

その後、そのスクリプトを現在の環境にロードし、2番目のスクリプトがその機能にアクセスできます。

自動化するには、~/.bashrcの下部に追加するだけです。

. /path/to/functional/script

これにより問題が解決します。

問題を誤って理解したか、sshコマンドにエラーがあるようです。

私のテストは次のとおりです。

ファイル:function_source.sh

#!/bin/bash

function testcall {

echo "now here I am"

}

ファイルdo_something.sh

#!/bin/bash

source ./function_source.sh

echo -e "This is called from within the script:\r\n"
testcall
echo -e "End Script - Any further output is from the function call:\r\n\r\n"

スクリプトファイルdo_something.shは、function_source.shのソースファイルをロードした後、function_source.shでtestcall関数を呼び出します。

ssh %server% "./do_something.sh; testcall"

出力:

-ssh %server% "./do_something.sh; テストコール"

これはスクリプト内で呼び出されます。

今私はここにいる

スクリプト終了 - 追加の出力は関数呼び出しから来ます。

bash:行1:testcall:コマンドが見つかりません

function_source.sh is .bashrcを参照し、.bashrcの末尾に次の行を追加します。

. ./function_source.sh

これで同じコマンドを実行します。

ssh %server% "./do_something.sh; testcall"

出力は次のとおりです

-ssh %server% "./do_something.sh; テストコール"

これはスクリプト内で呼び出されます。

今私はここにいる

スクリプト終了 - 追加の出力は関数呼び出しから来ます。

今私はここにいる

.bashrcでファイルを参照するのがうまくいかない唯一の方法は、.bashrcに次のものがある場合です。

case $- in
    *i*) ;;
      *) return;;
esac

.bashrcに対応するコードがある場合、sshを使用してコマンドを実行すると、.bashrc環境とソースファイルはロードされません。

注:これが標準のbashrcファイルとスクリプトファイルを使用するのではなく、最初から直接作成したり、すべての行を読んだり、各行の機能を知ったりする理由です。

他の設定を上書きするには、まずソースファイルをロードしてから関数を呼び出します。注:bashrcからソースコードへの参照を削除しました。

注文する:

ssh %server% ". ~/function_source.sh; testcall"

出力:

-ssh %server% ".~/function_source.sh; テストコール"

今私はここにいる

最後に、bashrcにソースファイルをロードし、sshを使用して関数を呼び出します。

注文する:

ssh %server% "testcall"

出力:

-ssh%server%"テストコール"

今私はここにいる

より多くの例が必要な場合はお知らせください。

注:Windowsのコマンドプロンプト(修正されたプロンプトは-)を使用してsshコマンドを実行し、プライバシーには%server%変数を使用し、認証にはsshキーを使用しました。

すべてを扱ったことを確認するために、terdonが提案したようにSSHを介してlocalhostに接続できるように、Linux仮想マシンの1つにSSHを移動しました。

また、関数ソースも修正しました。

-cat function_source.sh
#!/bin/bash

function testcall {

echo -e "now here I am\r\n\r\n"
testanother
}

function testanother {
        echo -e "this is another function\r\n\r\n"
}
 

次のコマンドを実行すると:

ssh localhost "$(typeset -f testcall); testcall"

出力:

-ssh localhost "$(typesetting -f testcall); testcall"

今私はここにいる

ただし、次のコマンドを実行すると:

ssh localhost "$(cat function_source.sh); testcall"

出力:

-ssh localhost "$(cat function_source.sh); テスト呼び出し"

今私はここにいる

これはもう一つの機能です。

これは、SSH接続しているサーバーへの書き込み権限がなく、毎回環境に関数をロードする必要がある場合にのみ実行できます。

関連情報