bashコマンドライン引数$ @と$ *へのアクセス


327

多くのSOの質問とbashチュートリアルで、bashスクリプトのコマンドライン引数に2つの方法でアクセスできることがわかります。

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

その結果:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

違いは何である$*とは$@
前者はいつ使用し、後者はいつ使用するのですか?


この答えを見てください:stackoverflow.com/a/842325/671366
コーディング

IntelliJの静的分析はecho "something $@"エラーとして扱われる
Alex Cohn

回答:


437

特別なパラメータが引用されている場合、違いが現れます。違いを説明しましょう:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

引用の重要性に関するもう1つの例:「arg」と数値の間に2つのスペースがあることに注意してください。ただし、$ wordを引用できない場合:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

そしてbashでは、"$@"反復する「デフォルト」リストです:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3

65
+1この概念は、bashのマニュアルが完全に欠けている単純な例で最もよく示されるといつも思っていました。
chepner 2012

5
可能なユースケースがあり、とき$*または"$*"必要になることがあり、&目的はで提供することができません$@"$@"
anishsane 2013

5
スクリプトラッパーが新しいコマンドのパラメーターになる必要がある「ラッパー」スクリプトにより適したバージョンはどれですか。
Segfault 2015年

7
この場合、@ Segfaultは常に"$@"引用符で選択します。
グレン・ジャックマン2015年

2
この回答には有用な例が含まれていますが、その背後にあるメカニズムも説明している方がよいでしょう。なぜこのように機能するのですか?
Lii

255

Bash Hackers Wikiの便利な概要表:

$ *対$ @テーブル

ここで、c3行目の最初の文字であり$IFS、内部電界セパレータ、シェル変数。

引数がスクリプト変数に格納され、引数にスペースが含まれることが予想される場合"$*"は、内部フィールドセパレーター$IFSをtabに設定したトリックを使用することを心からお勧めします


42
...ここで、「c」は$ IFSの最初の文字
です

39
...そして$IFS「Internal Field Separator」の略です。
Serge Stroobandt

以下は引用された入力を含むです。入力も重要です!
Serge Stroobandt 2017年

ラップされたコマンドの機能を模倣するだけのラッパースクリプトを作成するとします。ラッパースクリプトから内部コマンドに引数を渡すには、どの構文を使用する必要がありますか?
マリノス

44

$ *

1つから開始して、位置パラメーターに展開します。展開が二重引用符内で発生すると、IFS特殊変数の最初の文字で区切られた各パラメーターの値を持つ単一の単語に展開されます。つまり、「$ *」は「$ 1c $ 2c ...」と同等です。ここで、cはIFS変数の値の最初の文字です。IFSが設定されていない場合、パラメーターはスペースで区切られます。IFSがnullの場合、パラメーターはセパレーターを介さずに結合されます。

$ @

1つから開始して、位置パラメーターに展開します。展開が二重引用符で囲まれている場合、各パラメーターは個別の単語に展開されます。つまり、「$ @」は「$ 1」「$ 2」と同等です...単語内で二重引用符で囲まれた展開が発生した場合、最初のパラメータの展開が元の単語の最初の部分と結合され、展開最後のパラメータの最初の単語の最後の部分と結合されます。位置パラメータがない場合、「$ @」と$ @は何も展開しません(つまり、削除されます)。

ソース:バッシュマン


15

$ @は$ *と同じですが、各パラメーターは引用符付きの文字列です。つまり、パラメーターはそのまま解釈されずに渡されます。これは、とりわけ、引数リスト内の各パラメーターが個別の単語と見なされることを意味します。

もちろん、「$ @」は引用されるべきです。

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST


1

この例では、 "at"と "asterix"を使用しているときの違いを強調します。「フルーツ」と「野菜」の2つの配列を宣言しました

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

上記のコードの次の結果を参照してください。

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion

7
科学的に言えば、トマトは果物です。
ランディ

1
あなたは正しいです!「植物学では、果実は開花後に卵巣から形成される顕花植物(被子植物とも呼ばれます)の種子を持つ構造です。」 en.wikipedia.org/wiki/Fruit
stefansson

@ランディ:科学的に言えば、すべての果物は野菜です(「植物」の同義語です)。
クリスルエンゴ

@CrisLuengo異端です!:)
ランディ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.