
次の例があります。
#!/bin/bash
ARGUMENTS="-executors 1 -description \"The Host\" "
# call1
# error: parameter Host" is not allowed
java -jar swarm-client.jar $ARGUMENTS
# call2
# works fine with eval
eval java -jar swarm-client.jar $ARGUMENTS
から$ARGUMENTS
私は主張を引用します。引用の問題を解決するcall1
理由を理解できません。eval
シェルのコマンド評価のプロセスと順序を理解していないようです。私に説明してもらえますか?
答え1
あなたはしません引用された引数を渡すコマンドの場合、引数を渡すことができます。
入力するとき:
cmd arg1 arg2
シェルは、スペースが単語区切り文字である独自の構文で行を解析し、引数としてcmd1
呼び出されます。cmd
arg1
arg2
ノート:cmd
引数に空白文字を許可しません。スペースはシェル言語構文の演算子にすぎません。
Cと同様に、func("foo", "bar")
実行時に2つのポインタ引数を受け取って作成した場合、または空白文字はfunc
表示されません。(
,
"
シェル構文の一部も引用されます。"
シェル構文の他の部分を含む文字を含むことができる単語に使用されます。
これを行うとき:
cmd "arg 1" arg2
cmd
cmd
、arg 1
およびarg2
引数を受け取ります。何の文字も見えません"
。これは"
、シェル構文でスペースが単語区切り文字として扱われないようにするために使用されます。
今これを行う:
cmd $VAR
これは次のこととは異なります。
cmd the content of the variable
その場合、問題が発生します。
VAR='foo; reboot'
echo $VAR
例えば。
Bourne のようなシェルではの内容がどちら$VAR
にも単一引数で逐語的に渡されません (残念ながらこの問題は、およびそれより少ないcmd
一部の他のシェルでは修正されました)。rc
代わりに、分割とワイルドカード()が適用され、結果の単語がに渡されます。es
fish
zsh
split+glob
cmd
$IFS
分割は、デフォルトではスペース、タブ、および改行を使用する特殊変数の文字に基づいています。
$ARGUMENTS
含まれている内容については、、で-executors 1 -description "The Host"
区切ります。これらの単語にはワイルドカードが含まれていないため、glob部分は適用されないため、これらの単語はに渡されます。-executors
1
-description
"The
Host"
cmd
ここでは、演算子を使用し、split+glob
その単語に表示されない文字を区切り文字として使用して部分を分割できます。
ARGUMENTS='-executors|1|-description|The Host'
IFS='|'
cmd $ARGUMENTS
または、これをサポートするシェル(例bash
:)の場合はより良いです。配列の使用、これらのパラメータをすべて含む変数を含めることができます。
eval
シェルコードを評価することです。したがって、別のオプションは、ARGUMENTS
シェルコード(引数リストではなくシェル構文のテキスト)を含め、それをeval
解釈に渡すことです。しかし、分割+グローブ演算子を避けるために変数を引用することを忘れないでください。
eval "cmd $ARGUMENTS"
答え2
引用符が別の文字列内にある場合、bashはそれを別の文字として扱います。代わりに配列を使用してください。
args=(-executors 1 -description "The Host")
java -jar swarm-client.jar "${args[@]}"
この問題の詳細については、以下を参照してください。「コマンドを変数に入れようとしていますが、複雑なケースは常に失敗します!」。
また、変数名には小文字または大文字と小文字が混在する名前を使用してください。システムは変数名にすべて大文字を使用するため、誤ってそれらの1つを上書きしたくありません。
どのように動作しますか?
配列が定義されると、引用符args
で囲まれた個々の文字列が配列の個々の項目になります。以下を使用して配列の内容を調べると、declare -p arrayname
これを確認できます。
$ args=(-executors 1 -description "The Host")
$ declare -p args
declare -a args=([0]="-executors" [1]="1" [2]="-description" [3]="The Host")
ご覧のとおり、文字列はThe Host
配列の要素3です。
Bashが特別な型を拡張すると、"${args[@]}"
配列の各要素が別々の要素になります。言葉。これにより、文字列はThe Host
1つのままになります。言葉スペースが含まれていても同じです。