シェルの$ @のデータ構造は何ですか?


13

通常、$@$ 0を除くすべての引数を表すために使用します。ただし、データ構造$@が何であるかはわかりません。

$*二重引用符で囲むと動作が異なるのはなぜですか、誰でも通訳レベルの説明をくれますか?

forループで反復できるため、配列のようです。ただし、simple echo $@で完全にエコーすることもできます。配列の場合、最初の要素のみが表示されます。シェルの制限により、それを実行するための実験コードをこれ以上書くことができません。

この投稿の違い:この投稿は、どのように$@振る舞うかを示します$*。しかし、私はのデータ型について疑問に思っています$@。Pythonのような解釈言語としてのシェルは、一連の基本型に従ってデータを表現する必要があります。または、言い換えると、$ @がコンピューターのメモリーにどのように保存されているかを知りたいのです。

文字列、複数行の文字列、または配列ですか?

一意のデータ型の場合、カスタム変数をこの型のインスタンスとして定義できますか?


1
考えられる複製$ *と$ @の違い
ハクシエル

@ハクシエル、私はそうは思わない、私の投稿の一番下に彼らの違いを書いた。
ダブモス

あなたはより良いと出力の違いをテストすることによって提供されるだろうprintf '%s\n' "$@"printf '%s\n' "$*"echo彼らは、1つまたは多数ある場合、ユーティリティは、単に、関係なく、その引数を出力します。どちらも(文字列の)配列ですが、二重引用符で囲むと動作が異なります。どちらかが複数行の文字列である場合、複数行の文字列を保存することはできません(保存できます)。解決しようとしている問題は不明です。
クサラナナンダ

2
あなたの質問は、@var基礎となるストレージの観点から、Perlで変数が何であるかを尋ねることに相当します。通常のPerlプログラムの観点からは、配列/リストとしてアクセス可能であること(およびリストが期待されるコンテキストがあるという事実)以外は、実際には問題ではありません。
クサラナナンダ

回答:


16

それは、Bourneシェルのハックとして始まりました。Bourneシェルでは、リストコンテキスト内のすべての単語(コマンドライン引数またはforループがループする単語)に対してIFS単語分割が行われました(トークン化後)。持っていた場合:

IFS=i var=file2.txt
edit file.txt $var

二行目は3つのワードでトークン化されることは、$var拡大されるだろう、とあなたが実行して終わるだろうので、スプリット+グロブは、すべての3つの単語で行われることになるedtfle.txtfle2.txt引数として。

その一部を引用すると、split + globが妨げられます。Bourneシェルは、最初に8ビット目を内部に設定することで、引用された文字を記憶しました(Unixが8ビットクリーンになったときに変更されましたが、シェルは引用されたバイトを記憶するのと同じようなことをしました)。

両方$*$@インとの間の空間との位置パラメータを連結しました。しかし、$@二重引用符の内側にあるときの特別な処理がありました。$1包含foo barおよび$2包含の場合baz、次の"$@"ように展開されます。

foo bar baz
^^^^^^^ ^^^

^上記のsは、どの文字に8番目のビットが設定されているかを示します)。最初のスペースが引用された(8番目のビットが設定されていた)が、2番目のスペース(単語の間に追加されたもの)は引用されていません。

そして、引数の分離を処理するのはIFS分割です(スペース文字が$IFSデフォルトのままであると仮定)。これ$*は、前身のMasheyシェル(それ自体がThomsonシェルに基づいており、Bourneシェルはゼロから作成された)で拡張された方法に似ています。

これは、Bourneシェル"$@"で、位置パラメーターのリストが空のときに何もではなく空の文字列に最初に展開する理由(を使用して回避する必要がありました${1+"$@"})、空の位置パラメーターを保持しない理由"$@"$IFSスペース文字が含まれていないと機能しません。

引数のリストを別のコマンドに逐語的に渡すことができるようにすることでしたが、それは空のリスト、空の要素、または$IFSスペースが含まれていない場合には正常に機能しませんでした(最初の2つの問題は後のバージョンで修正されました) )。

POSIX仕様のベースであるKornシェルは、いくつかの方法でその動作を変更しました。

  • IFS分割のみ(ないような文字通りの言葉に引用符で囲まれていない拡張の結果で行われるeditか、file.txt上記の例では)
  • $*そして、空の場合は$@最初の文字$IFSまたはスペースで結合$IFSされますが"$@"、quoterの場合はジョイナーはBourneシェルのように引用されず、引用された"$*"場合IFSは空の場合、位置パラメーターはセパレータなしで追加されます。
  • それはアレイのサポートを追加し、そしてと${array[@]} ${array[*]}ボーンのを連想させる$*$@が、その手段indice 0の代わりに1、および(より連想配列のような)の疎始まる$@と比較kshのアレイ(として実際に処理することができませんcsh/ rc/ zsh/ fish/ yashここで、$argv/は$*正常です配列)。
  • 空の要素は保持されます。
  • "$@"when $#is 0は空の文字列の代わりに何も展開せず、when が空の場合を除いてスペースが含まれていない"$@"場合に$IFS機能しIFSます。$*ワイルドカードなしの引用符なし$IFSは、空の場合、1つの引数(位置パラメーターがスペースで結合されている)に展開されます。

ksh93は、上記の残りのいくつかの問題を修正しました。ksh93、内$*及び$@位置パラメータのリストに展開さの値にかかわらず分離$IFSし、その後さらに分割+グロビングされ+ブレース展開、リストコンテキストで$*最初に接合バイトの(ない文字)$IFS"$@"リストにリストコンテキストの拡大に位置パラメータのかかわらず、の値$IFS。非リストコンテキストでは、のようにvar=$@$@の値にかかわらず空間と接合されています$IFS

bashの配列は、ksh配列の後に設計されています。違いは次のとおりです。

  • 引用符で囲まれていない展開時のブレース展開なし
  • $IFSバイトではなくの最初の文字
  • $*when $IFSが空の場合の非リストコンテキストでの非引用時の拡張など、いくつかのコーナーケースの違い。

POSIX仕様は以前はかなり曖昧でしたが、現在では多かれ少なかれbashの動作を指定しています。

それはで、通常の配列と異なるのですkshbashという点で:

  • インデックスは0ではなく1から始まります(ただし、"${@:0}"インクルード$0(位置パラメータではなく、関数内では関数の名前を提供するか、シェルおよび関数の定義方法に依存しない)を除く)。
  • 要素を個別に割り当てることはできません
  • スパースではなく、要素を個別に設定解除することはできません
  • shift に使える。

zshまたはyashアレイが正常アレイである場合(ないスパース、インデックスが他のすべてのシェルが、kshの/ bashでのようなもので開始)、$*通常の配列として扱われます。zsh$argvエイリアスとして使用します(との互換性のためcsh)。or $*と同じです(引数はリストコンテキストの最初の文字と結合されていますが、まだ分離されています)。Kornスタイルの特別な処理を好む、または受けます。$argv${argv[*]}$IFS"$@""${argv[@]}""${*[@]}"}


8

ただし、データ構造$@が何であるかはわかりません。

これは、位置パラメータの値に展開される特別なパラメータです...しかし、それは用語については細心の注意を払っています。

位置パラメータはの一部として見ることができます$@。したがって、独立してアクセスでき、連続する自然数で名前が付けられた多数の個別の要素($1$2...)があります。これにより、通常は配列と呼ばれるものになります。

しかし、構文は少し奇妙で、制限さえあります。配列の単一の要素を個別に変更する方法はありません。代わりに、すべてを一度に設定する必要があります。(set -- "$@" foo値を追加したりset -- "${@:1:2}" foo "${@:3}"、中央に値を追加したりできます。ただし、どちらの場合も、結果リスト全体を書き出す必要があります。)

$*二重引用符で囲む場合と異なる動作をする理由、

異なる動作をするように定義されているからです。

ただし、simple echo $@で完全にエコーすることもできます。配列の場合、最初の要素のみが表示されます。

a=(foo bar asdf); echo $aちょうど出力するという事実を意味する場合foo、これは主にシェル構文の癖であり、kshスタイルの名前付き配列が位置パラメータとの後に作成されたという事実です$@。Plain $aは、配列と単純スカラー変数のどちら${a[0]}であるかに関係なく、単一のスカラー値の下位互換性のある意味を持つのと同じaです。

@リスト全体を参照符号は、その中に名前の配列を再利用した"${a[@]}"全体のリストを取得する方法です。名前付き配列と比較して、を使用する$@と、不要な中括弧と角括弧、および名前はスキップされます。

言い換えれば、$@コンピューターのメモリにどのように保存されているかを知りたいのです。

それは実装に依存しますので、気になる特定のシェルのソースコードを調べる必要があります。

文字列、複数行の文字列、または配列ですか?

主に配列。kshスタイルの名前付き配列とは異なりますが、インデックスのように連続したものだけでなく、任意の非負整数をインデックスとして使用できるため$@です。(これはという名前の配列が疎であること、および例えば、インデックスを持つことができ、ある134、と0し、2不足している。それは位置パラメータとはできません。)

個別の要素に展開できるため、単一の文字列ではありません。また、通常の変数または位置パラメータ(の要素$@)の1つにも改行を含めることができるため、要素行の呼び出しも正しくありません。

一意のデータ型の場合、カスタム変数をこの型のインスタンスとして定義できますか?

いいえ。しかし、とにかく名前付き配列はおそらくより便利です。


1
+1。TL:DR $@はデータ構造ではなく、位置パラメータデータ構造を拡張するための数少ない関数/演算子の1つです。
ピーター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.