Bashスクリプトは、SSH経由で呼び出されたときにのみ「バインドされていない変数」エラーを発生させます。

Bashスクリプトは、SSH経由で呼び出されたときにのみ「バインドされていない変数」エラーを発生させます。

私が実行したとき:

ssh [email protected] bash -c "/home/devops_staging/deployJob.sh example"

次のエラーが発生します。

/home/devops_staging/deployJob.sh: line 4: $1: unbound variable

その部分なしで実行すると、期待bash -cどおりに動作します。

ssh [email protected] /home/devops_staging/deployJob.sh example
deploy success

なぜこれが起こるのですか?

ssh ... bash -c "commands param1 param2"私はいつもこの構文を問題なく使用したことを覚えているようですので、これは非常に予期しないことです。

問題のスクリプトは非常に簡単です。行4で私がすることは変数を割り当てるだけです$1(これが最初のパラメータでなければなりません)。

#!/usr/bin/env bash
set -euo pipefail

CI_PROJECT_NAME="$1"
...

デバッグ中に、bash -x -c ...次の疑わしい行が表示されます。

 + '[' -z '' ']'
 + return
 + case $- in
 + return
 + /home/devops_staging/deployJob.sh
/home/devops_staging/deployJob.sh: line 4: $1: unbound variable

答え1

私はこれが次の質問と重複していると思います。引用された SSH コマンド。すでに気付いていますが、著者はここで次のように指摘しています。

この記事を読んだ後も、なぜこれがうまくいくのかわかりません。

したがって、この回答は、現在の質問で使用されているコードの文脈で問題を具体的に説明しようとします。

最も重要な情報はここにあります。リンクされた質問に対する良い答え例:

SSH はシェルからリモートコマンドを実行します。パラメータリストの代わりに文字列をリモートシェルに渡します。コマンドに渡されたパラメーターはsshスペースで区切られます。

ローカルで実行している場合

ssh [email protected] /home/devops_staging/deployJob.sh example

これにより、sshパラメータがリモートエンドに渡されると識別されるコードは次のようになります/home/devops_staging/deployJob.shexample関連付けられたパラメータ文字列は次のとおりです。

/home/devops_staging/deployJob.sh example

これはリモート側で実行されるシェルコードです。これがあなたが望む文字列である場合があります。

しかし、ローカルで実行すると

ssh [email protected] bash -c "/home/devops_staging/deployJob.sh example"

これでパラメータは次のようになります。リモートbashシェルの文字列は次のとおりです。-c/home/devops_staging/deployJob.sh example

bash -c /home/devops_staging/deployJob.sh example

bash(パラメータが、、、、で-cある/home/devops_staging/deployJob.shかのようにexample)これは次のとおりです。いいえリモート側で実行したいシェルコードです。これはexampleオプションパラメータではありません(2番目のパラメータ-cと同じ)。shこれはもう一つの質問です。)。

この文字列をリモートコードとして使用するには、次の手順を実行します。

bash -c "/home/devops_staging/deployJob.sh example"

次に、最も簡単な方法は、ssh文字列を単一の引数としてローカルに渡すことです。

ssh [email protected] 'bash -c "/home/devops_staging/deployJob.sh example"'

一重引用符引数には、リモートSSHサーバーが起動したシェルに渡されるすべてのシェルコードが含まれます。

これはローカルでも実行できます。

ssh [email protected] 'bash -c "/home/devops_staging/deployJob.sh' 'example"'

二重引用符(リモートシェルの場合)が2つの別々のローカルパラメータに属する場合、リモートシェルの結果文字列は同じです。


(リモート)コードがdeployJob.sh実行されるまで、どのように多くのツールがこのコマンドを解釈して消化しているかを確認してください。

  1. ローカルシェルは単語分割、引用符の削除(そしてしばしばいくつかの異なるタスク)を実行します。結果はssh1つ以上のパラメータにすることができ、これはリモートエンドに渡されるコードとして解釈されます。

  2. ssh単一の文字列をリモートシェルに渡すには、これらの引数を中間スペースに関連付けます。

  3. リモートシェルは、それ自体で単語分割、引用符の削除(および一般にいくつかの他のタスク)を実行します。いくつかのコマンドを実行します。

  4. コマンドがbash -c …別の(リモート)コマンドの場合、シェルはコードをオプション引数として解析します-c。トークン化、引用符の削除、その他の操作もシェルで行われます。

  5. deployJob.sh正気のshebangが含まれている場合(または)これにより、他の(リモート)シェルがファイルを順番に解釈します。

通常、以前のすべてのツールがそのパラメータを消化した後、どのツールがどのパラメータを取得するのか、どのパラメータが次のツールに渡されるかを予測して戦略を立てる必要があります。最終ツールが目的の結果を正確に取得できるように、基本的なコマンドを設計する必要があります。

関連情報