bashはポインターの使用をサポートしていますか?


12

簡単な質問。bashシェルは、シェルスクリプトを記述するときにポインターを使用することをサポートしていますか?

${var[@]}配列を反復処理するときの拡張表記法に精通して$varいますが、これが配列インデックスを反復処理するためにポインターを利用していることは明らかではありません。bashは他の言語のようなメモリアドレスへのアクセスを提供しますか?

bashがポインターの使用をサポートしていない場合、他のシェルは何をしますか?

回答:


28

メモリの場所への)ポインタは、Pythonやシェルのようなものであっても、Cよりも高いレベルでは実際には有用な概念ではありません。もちろん、オブジェクトへの参照は高レベル言語で役立ち、おそらく複雑なデータ構造を構築するためにも必要です。しかし、ほとんどの場合、メモリアドレスの観点から考えると、非常に役立つには低レベルです。

Bash(および他のシェル)では、${array[index]}表記法を使用して配列要素の値を取得し、割り当ててarray[index]=...、配列要素の数を取得でき${#array[@]}ます。括弧内の式は算術式です。構成例として、すべての配列メンバーに定数プレフィックスを追加できます。

for ((i=0 ; i < ${#array[@]} ; i++ )) ; do
    array[i]="foo-${array[i]}"
done

(インデックスではなく、値だけに関心がある場合は問題ありませんfor x in "${array[@]}" ; do...。)

連想またはスパース配列、数値ループはあまり意味がありませんが、その代わり、私たちはして配列のキー/インデックスを取得する必要があると思います${!array[@]}。例えば

declare -A assoc=([foo]="123" [bar]="456")
for i in "${!assoc[@]}" ; do 
    echo "${assoc[$i]}"
done 

それに加えて、Bashには別の変数を間接的に指す2つの方法があります。

  • 名前がの変数の値を使用する${!var}構文を使用し間接展開、およびvar
  • namerefsdeclare組み込み(またはksh-compatibleシノニムtypeset)で作成する必要があります。declare -n ref=varなりref、変数への参照をvar

Namerefsもサポートインデックス、我々が持っている場合ということでarr=(a b c); declare -n ref=arr;、その後${ref[1]}に展開されますb${!p[1]}代わりにp配列を使用し、2番目の要素で指定された変数を参照します。

bashで、namerefsは参照することにより、という文字通り、および関数内からnamerefを使用すると、指定された変数のローカル値を使用します。これは印刷されますlocal value of var

#!/bin/bash
fun() {
        local var="local value of var"
        echo "$ref";
}
var="global var"
declare -n ref=var
fun

BashFAQには、間接化に関する長い記事もあります。


2
インダイレクションは、高レベルの言語では非常に便利です。たとえば、perlの参照。これらはCポインターと同じではありませんが、同じ基本機能を提供します。bashでさえ間接的に変数にアクセスできますが、IMOを使用して、この機能を大幅に使用するコードの記述を開始する場合は、perlなどを使用してゼロから始める方が適切です。mywiki.wooledge.org/BashFAQ/006
cas

2
@cas、ああ、絶対に。ただし、メモリアドレスではなくオブジェクトを指していると考える方がおそらく良いでしょう。(Cでも、型が関係しています。)間接展開と名前参照の両方に注意するつもりでしたが、すぐにそれを行う時間はありませんでした。
ilkkachu

for foo in "${array[@]}" ; do ... done他の目的のためにインデックスが必要でない限り、forループの例はより自然に書かれていることを指摘する価値があるでしょう。
ウィルクロフォード

@WillCrawford、ポイント。例を編集し、書き留めました。
ilkkachu

9

いいえ、bash「ポインター」はありませんが、参照はあります。

$ spam="fred"
$ declare -n tripe=spam
$ echo $tripe
fred
$ tripe=juki
$ echo $spam
juki

bashmanページから:

変数にnameref属性を割り当てるには、-nオプションを使用して、declareまたはlocal組み込みコマンドを使用して、namerefまたは別の変数への参照を作成します。これにより、変数を間接的に操作できます。nameref変数の参照、割り当て、設定解除、または属性の変更(nameref属性自体の使用または変更以外)が行われるたびに、実際には、nameref変数の値で指定された変数に対して操作が実行されます。namerefは一般的にシェル関数内で使用され、関数に引数として渡される名前を持つ変数を参照します。たとえば、変数名が最初の引数としてシェル関数に渡された場合、次を実行します

declare -n ref=$1

関数内で、nameref変数refを作成します。この変数の値は、最初の引数として渡された変数名です。refへの参照と割り当て、およびその属性の変更は、名前が$ 1として渡された変数への参照、割り当て、および属性の変更として扱われます。forループの制御変数にnameref属性がある場合、単語のリストはシェル変数のリストにすることができ、ループが実行されると、リスト内の各単語に対して名前参照が確立されます。配列変数にnameref属性を与えることはできません。ただし、nameref変数は、配列変数と添え字付き配列変数を参照できます。Namerefは、unset組み込みの-nオプションを使用して設定解除できます。そうでなければ、unset nameref変数の名前を引数として実行すると、nameref変数によって参照される変数は設定解除されます。


4

いいえ、シェルは「ポインター」を使用しません(Cで理解されています)。

配列はインデックスを使用できます。echo "${array[2]}"しかし、@あなたの例では実際には「ポインタ」ではありません。「配列値のリスト」を表現する方法です。シェルパーサーが理解できるもの。方法と同様:

$ echo "$@"

すべての「位置パラメータ」リストに展開します。


2

bash整数のインデックス付き配列は、そのように繰り返し定義およびアクセスできます。

declare -a obj
obj+=("val1")
obj+=("val2")

for item in ${obj[@]}; do
  echo "${obj[${item}]} ${item}"
done

bashの連想配列または文字列ベースのインデックス配列には、次の反復定義が必要です。

declare -A obj
obj["key1"]="val1"
obj["key2"]="val2"

for item in ${!obj[@]}; do
  echo "${obj[${item}]} ${item}"
done

ポインターに関する質問に回答し、bashのポインターを使用するには; コンパイルされたbashバイナリの内部機能は、スタックに割り当てられたメモリへのポインターを実際に使用し、を使用して同様の機能を公開しますeval。[間接参照] http://tldp.org/LDP/abs/html/ivr.htmlを参照してください)

ドラゴンがいます。の使用はeval、セキュリティへの影響があるため、注意して使用する必要があります

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