私は別のスクリプトを呼び出す非常に単純なスクリプトを書いており、現在のスクリプトから実行中のスクリプトにパラメーターを伝達する必要があります。
たとえば、私のスクリプト名はでfoo.sh
、bar.sh
foo.sh:
bar $1 $2 $3 $4
各パラメーターを明示的に指定せずにこれを行うにはどうすればよいですか?
私は別のスクリプトを呼び出す非常に単純なスクリプトを書いており、現在のスクリプトから実行中のスクリプトにパラメーターを伝達する必要があります。
たとえば、私のスクリプト名はでfoo.sh
、bar.sh
foo.sh:
bar $1 $2 $3 $4
各パラメーターを明示的に指定せずにこれを行うにはどうすればよいですか?
回答:
パラメータを同じように渡したい場合"$@"
は、プレーンの代わりに使用し$@
ます。
観察する:
$ cat foo.sh
#!/bin/bash
baz.sh $@
$ cat bar.sh
#!/bin/bash
baz.sh "$@"
$ cat baz.sh
#!/bin/bash
echo Received: $1
echo Received: $2
echo Received: $3
echo Received: $4
$ ./foo.sh first second
Received: first
Received: second
Received:
Received:
$ ./foo.sh "one quoted arg"
Received: one
Received: quoted
Received: arg
Received:
$ ./bar.sh first second
Received: first
Received: second
Received:
Received:
$ ./bar.sh "one quoted arg"
Received: one quoted arg
Received:
Received:
Received:
'arg with spaces'
3つの例にを含めるとどうなるかを示すこともお勧めします。結果に驚いた。うまくいけば、あなたはそれらを説明することができます。
./foo.sh "arg with spaces"
と./foo.sh 'arg with spaces'
私は与えられた例に追加の提案が任意の助けになるだろうか見ていないので、100%同じです。
以下のためのbashや他のBourneのようなシェル:
java com.myserver.Program "$@"
$argv:q
いくつかのcshバリアントで動作すると思います。
exec java com.myserver.Program "$@"
これにより、bashが完了するまで待つのではなく、Javaにexecが実行されます。したがって、使用するプロセススロットが1つ少なくなります。また、親プロセス(スクリプトを実行したプロセス)がpidを介してそれを監視していて、それが「java」プロセスであると予期している場合、execを実行しないと、異常な事態が発生する可能性があります。execはjavaに同じpidを継承させます。
args=("$@")
、別のシェル「単語」として、各要素を展開します(と似ている"$@"
)"${args[@]}"
。
"$@"
、引数内のスペース、null文字、またはその他の特殊文字をエスケープすると失敗するのですか?
$*
。ここには歴史的な進展があると思います。$*
設計どおりに機能しなかったため、それ$@
を置き換えるために発明されました。しかし、引用ルールはそれらが何であるかであり、それを囲む二重引用符は依然として必要です(または、壊れた$*
セマンティクスに戻ります)。
echo "$@"
as を含むスクリプトを呼び出すと、の代わりにが./script.sh a "b c" d
取得されa b c d
ますがa "b c" d
、これは大きく異なります。
echo
3つの引数を受け取るので安心してください"a" "b c" "d"
(シェルはそれらを文字列展開の一部として結合します)。しかし、あなたが使っていたなら、あなたfor i in "$@"; do echo $i; done
は得たでしょうa⏎b c⏎d
。
これはよく答えられていると思いますが、これは "$ @" $ @ "$ *"と$ *の比較です
テストスクリプトの内容:
# cat ./test.sh
#!/usr/bin/env bash
echo "================================="
echo "Quoted DOLLAR-AT"
for ARG in "$@"; do
echo $ARG
done
echo "================================="
echo "NOT Quoted DOLLAR-AT"
for ARG in $@; do
echo $ARG
done
echo "================================="
echo "Quoted DOLLAR-STAR"
for ARG in "$*"; do
echo $ARG
done
echo "================================="
echo "NOT Quoted DOLLAR-STAR"
for ARG in $*; do
echo $ARG
done
echo "================================="
次に、さまざまな引数を指定してテストスクリプトを実行します。
# ./test.sh "arg with space one" "arg2" arg3
=================================
Quoted DOLLAR-AT
arg with space one
arg2
arg3
=================================
NOT Quoted DOLLAR-AT
arg
with
space
one
arg2
arg3
=================================
Quoted DOLLAR-STAR
arg with space one arg2 arg3
=================================
NOT Quoted DOLLAR-STAR
arg
with
space
one
arg2
arg3
=================================
#!/usr/bin/env bash
while [ "$1" != "" ]; do
echo "Received: ${1}" && shift;
done;
引数がスクリプトにどのように取り込まれるかをテストするときに、これがもう少し便利かもしれないと思っただけです
$#
""
、''
何の引数がなかった場合も、それは沈黙している、引数として。私はこれを修正しようとしましたが、forループとでのカウンターが必要$#
です。これを最後に追加しました:echo "End of args or received quoted null"
含める場合 $@
引用符で囲まれた文字列に他の文字、複数の引数がある場合の動作は非常に奇妙であり、最初の引数のみが引用符内に含まれます。
例:
#!/bin/bash
set -x
bash -c "true foo $@"
収量:
$ bash test.sh bar baz
+ bash -c 'true foo bar' baz
しかし、最初に別の変数に割り当てる:
#!/bin/bash
set -x
args="$@"
bash -c "true foo $args"
収量:
$ bash test.sh bar baz
+ args='bar baz'
+ bash -c 'true foo bar baz'
"$@"
、bashのセマンティクスの範囲内で理にかなっています。また、との主な違い$@
と$*
、両方がなぜ有用であるかを説明するのにも役立ちます。bash(1)
manページ特殊パラメータセクション:「*
-ダブルクォートの内部で展開が行われた場合、それは各パラメータの値を持つ単一の単語に展開されます[...]である、"$*"
と等価である"$1c$2c..."
場合は、c
[あります$IFS
]。」そして実際、最初の例の$*
代わりにを使用$@
すると、2番目のバージョンと同じ出力が得られます。
"$@"
。再びmanページから: " @
—二重引用符内で展開が行われると、各パラメーターは個別の単語に展開されます。つまり、… "$@"
と同じ"$1"
"$2"
です。二重引用符で囲まれた展開が単語内で発生すると、最初のパラメーターの展開が結合されます元の単語の最初の部分で、最後のパラメータの展開が元の単語の最後の部分と結合されます。」...そして実際、もしあなたのコードがそうだったならbash -c "true foo $@ bar baz"
、それtest.sh one two
をnetのように実行しbash -c 'true foo one' 'two bar baz'
ます。
$*
、私はそれが存在していることを忘れているようだ...
$@
私が最初にシェルスクリプトを始めたとき、ちょうど引き付けられていました。それがまだあることを思い出さなければなりません。"$*"
スクリプトで使用されるのが一般的でした...それから著者はそれがすべての引数を一緒に壊していることに気づくでしょう、それで彼らは複雑なナンセンスのすべての方法を単語分割"$*"
で試すか、ループすることによって引数リストを[再]組み立てますオーバーshift
だけ使用して...一つ一つ下のそれらを引っ張って$@
解きにそれを。(bashが同じニーモニックを使用して配列のメンバーにアクセスすることも支援します。${var[*]}
それらはすべて単語として、単語${var[@]}
のリストとして。)
bash -c
まったく意味のない方法で使用していることです。
スペースやエスケープ文字がある場合を除いて、正常に機能します。この場合、引数をキャプチャしてスクリプト内のSSHに送信する方法が見つかりません。
これは便利かもしれませんがとても醜いです
_command_opts=$( echo "$@" | awk -F\- 'BEGIN { OFS=" -" } { for (i=2;i<=NF;i++) { gsub(/^[a-z] /,"&@",$i) ; gsub(/ $/,"",$i );gsub (/$/,"@",$i) }; print $0 }' | tr '@' \' )
ここでは多くの回答が推奨されている$@
か$*
、または引用符が付いていないかを示していますが、これらが実際に何をするのか、なぜそうすべきなのかを説明している人はいません。だから私はこの答えからこの素晴らしい要約を盗みます:
引用符はすべての違いを生むことに注意してください。引用符がないと、どちらも同じ動作になります。
私の目的のために、あるスクリプトから別のスクリプトにパラメーターをそのまま渡す必要があり、そのための最良のオプションは次のとおりです。
# file: parent.sh
# we have some params passed to parent.sh
# which we will like to pass on to child.sh as-is
./child.sh $*
引用符は$@
なく、上記の状況でも同様に機能することに注意してください。
bar "$@"
と同等になります bar "$1" "$2" "$3" "$4"
引用符が重要であることに注意してください!
"$@"
、$@
、"$*"
または$*
この中に記載されるようにエスケープおよび連結についてなる各挙動わずかに異なります stackoverflowの答えが。
密接に関連する使用例の1つは 、次のような引数内のすべての指定された引数を渡すことです。
bash -c "bar \"$1\" \"$2\" \"$3\" \"$4\""
。
私はこれを達成するために@kvantourの答えのバリエーションを使用します:
bash -c "bar $(printf -- '"%s" ' "$@")"