Bashの「ドア」とは何ですか?

Bashの「ドア」とは何ですか?

かっちゅさんの回答を読んだ後この問題declare組み込み(パラメータを含む)シェルの存在について学びました。-n

help declareインポート:

変数の値と属性を設定します。

変数を宣言し、属性を割り当てます。名前を指定しないと、すべての変数の属性と値が表示されます。

-n...NAME を値の名前付き変数への参照にします。

変数が何であるか、拡張するのかわからないので、declare例と一緒に一般的な説明を求めました。しかし、まだ(変数プロパティ?)を見逃しています。manmandeclare

答えのilkkachuのコードに基づいてこれを説明したいかもしれません。

#!/bin/bash
function read_and_verify  {
    read -p "Please enter value for '$1': " tmp1
    read -p "Please repeat the value to verify: " tmp2
    if [ "$tmp1" != "$tmp2" ]; then
        echo "Values unmatched. Please try again."; return 2
    else
        declare -n ref="$1"
        ref=$tmp1
    fi
}

答え1

ほとんどの場合、暗黙の宣言で十分です。bash

asdf="some text"

しかし、時には変数の値が整数になることを望むかもしれません。したがって、後で自動的に変更しても整数にのみ変更されることがあり、場合によってはデフォルト値は0になります。以下を使用できます。

declare -i num

または

declare -i num=15

時には配列が必要で、その後は必要です。declare

declare -a asdf   # indexed type

または

declare -A asdf   # associative type

bashたとえば、検索文字列 "bash arraytutorial"(引用符を除く)を使用してインターネットを閲覧するときに配列の優れたチュートリアルを見つけることができます。

linuxconfig.org/how-to-use-arrays-in-bash-script


変数を宣言するときに最もよく発生するケースだと思います。


また参考にしてください

  • 関数内のdeclare変数をローカルにします(関数内)。
  • 名前がない場合は、すべての変数が一覧表示されます(アクティブシェルにあります)。

    declare
    

declare最後に、以下を使用して、bashシェルの組み込みコマンド機能の簡単な要約を得ることができます。

help declare

答え2

出力はhelp declare非常に簡潔です。より明確な説明はman bashorで見つけることができますinfo bash。後者は、次の内容のソースです。

まず、いくつかの定義です。 ~について変数と属性:

範囲値を格納するエンティティです。 ...ㅏ変えるで表されるパラメータですname。変数にそしてゼロ以上プロパティ。組み込みコマンドを使用した属性の割り当てdeclare...

また、薬declare 組み込み:

declare

declare [-aAfFgilnrtux] [-p] [name[=value] …]

変数を宣言し、属性を割り当てます。名前が指定されていない場合は、変数の値が表示されます。

...

-n
それぞれに名前これ名前参照属性を他の変数の名前参照にします。この他の変数は次の値で定義されます。名前。すべての参照、割り当て、属性の変更名前、属性自体を使用または変更することを除いて、以下-nで参照される変数に対して行われます。名前値。 ...

気づく名前参照変数はBash 4.3以上1でのみ使用できます

また、declareBashの変数属性の有用な紹介のために、以下をお知らせします。この回答「何をしdeclare namedeclare -g何をすべきですか?」(主に変数の範囲に焦点を当てます)。


基本的に2はあなたになじみのある宿題declare name=[value]のようです。name=[value]どちらの場合も、欠落している場合はnameNULL値が割り当てられます。value

declare name少し異なりますが、その逆ではありません。置く変数name3 :

$ declare name

## With the -p option, declare is used to display
## attributes and values of variables
$ declare -p name
declare -- name            ## "name" exists

## Parameter expansion can be used to reveal if a variable is set:
## "isunset" is substituted to "name" only if unset 
$ echo "${name-isunset}"
isunset

したがって、変数は次のようnameになります。

  • 発表するそして未設定、後ろにdeclare name
  • 発表するそして置くそして無効値としてname=またはそれ以降declare name=
  • 発表する置くそして空ではないname=valueまたはそれ以降の値declare name=value

より一般的には、declare [options] name=value

  1. 変数の作成 - これは名前付きパラメータであり、情報をname格納するために使用できるメモリの一部にすぎません4。
  2. それに値を割り当てますvalue
  3. nameオプションで保存できる値の種類を定義する属性を設定します。タイプ、厳密に言えば、Bashの言語は入力されていないので)と動作する方法です。

たとえば、プロパティを記述する方が簡単です。を使用すると、declare -i name「整数」プロパティはname整数参照として処理されるように設定されます。手動、「変数が代入されると算術演算が実行されます」:

## Let's compare an ordinary variable with an integer
$ declare var
$ declare -i int
$ var="1+1"
$ int="1+1"
$ echo "$var"
1+1                 ## The literal "1+1"
$ echo "$int"
2                   ## The result of the evaluation of 1+1

上記を考えると、ilkkachuのコードで何が起こるかは次のとおりです。

  1. nameという変数を宣言し、ref「nameref」属性を設定した後$1(最初の位置引数)の内容を割り当てます。

    declare -n ref="$1"
    

    名前参照変数の目的refは、通常、事前に未知の他の変数の名前を保持することです。それはおそらく動的に定義したいので、いくつかの変数(たとえば、コードスニペットを再利用して適用したいため)に適用し、それを参照(および操​​作)する便利な方法を提供します。 (しかし唯一のものではありません:間接参照が代替です。シェルパラメータ拡張)。

  2. 変数の値がtmp1割り当てられる場合ref:

    ref=$tmp1
    

    ref名前が値の追加変数が暗黙的に宣言されます。のtmp1価値間接的にへの明示的な割り当てを介して暗黙的に宣言された変数に割り当てますref

そのような状況ではリンクに問題があります、次read_and_verifyのように呼び出されます

read_and_verify domain "Prompt text here..."

変数が宣言さdomainれ、値tmp1(つまり、ユーザー入力)が割り当てられます。これは、ユーザーと対話し、nameref変数を使用して宣言するコードdomainやその他の変数を再利用するように設計されています。

暗黙の部分を詳しく見るために、プロセスを段階的に再現できます。

## Assign a value to the first positional argument
$ set -- "domain"

## Declare the same "tmp1" variable as in your code
$ tmp1="value for domain"

## Declare a "ref" variable with the nameref attribute set and
## assign the value "domain" to it
$ declare -n ref="$1"

## Note that there is no "domain" variable yet
$ declare -p domain
bash: declare: domain: not found

## Assign a value to "ref" and, indirectly, to the "domain" variable
## that is implicitly declared  
$ ref=$tmp1

## Verify that a variable named "domain" now exists, and that
## its value is that of "tmp1"
$ declare -p domain
declare -- domain="value for domain"

## Verify that "ref" is actually a reference to "domain"
$ domain="new value"
$ echo "$domain"
new value
$ declare -p ref
declare -n ref="domain"
$ echo "$ref"
new value

1参考資料多様性ファイルの「3. Bashの新機能」セクションで「w」をクリックしてください。
これは関連している可能性があります。たとえば、CentOS Linux 7.6(現在の最新バージョン)バッシュ4.2に付属

2.シェル内蔵機能と同じ、詳細そして多様で異質な作業を行うため、簡潔な説明は困難です。私は、属性の宣言、割り当て、設定にのみ焦点を当て、属性のリスト、スコープ、削除について検討します。これはこの回答の範囲外です。

3この動作はBash 4.4 で導入されました。引用:declare -p多様性ファイルの「3. Bashの新機能」セクションで「f」をクリックします。
〜のようにG-マンBash 4.3でdeclare name; declare -p nameエラーが発生することがコメントに記載されています。ただし、nameを使用して存在を確認できますdeclare -p | grep 'declare -- name'

4つの完全なBashガイド、パラメータmywiki.wooledge.orgから

答え3

これについて説明しようと思いますが、提供された例に従わない場合でもご了承ください。むしろ私はあなたに自分自身の他のアプローチを案内しようとしています。

「変数」や「拡張」などの概念をすでに理解していると言われているので、いくつかの背景知識だけを見て、そうでなければより深い焦点が必要です。

だから私が最初に言いたいことはせいぜい基本的なレベルでは、このdeclareコマンドはBashに変数の値(スクリプトの実行中に変更される可能性がある値)が必要なだけで、特定の名前、正確に名前を使用してその値を参照することを通知するだけです。コマンドdeclare自体の横に指定します。

それは:

declare foo="bar"

Bashに名前付き変数fooに値があることを知らせてくださいbar

しかし、..ちょっと待ってください..declare使用せずにこれを行うことができます。そうですか?良い:

foo="bar"

とても本当です。

さて、上記の簡単な割り当ては実際には絶対的な実際に..変数を宣言する方法です。

上記と同じことが発生しました。一つさまざまな方法変化;という変数の値はfoo実際に最も直接的で、簡潔で、明確で、簡単な方法です...しかし、これが唯一の方法ではありません...これについては後でもう一度説明します...)。

しかし、「変数の値を表示する名前」(以下では簡潔に「変数」と呼ぶ)を使用せずに宣言することが完全に可能な場合は、なぜdeclare この途方もない「宣言」コマンドを使用しますか?

答えは変数()を宣言する暗黙の方法にありますfoo="bar"。これは...暗黙的に... Bashは、変数が一般的なシェル使用シナリオで最も一般的に使用される型であると考えさせます。

この型は、特定の意味のない一連の文字である文字列型です。したがって、暗黙的な宣言を使用すると文字列が得られます。

ただし、プログラマは時々変数を数値として扱う必要があります。変数に対して算術演算を実行し、次の暗黙的な宣言を使用する必要があります。foo=5+6 に慣れるfooBashが意図したとおりに値11を割り当てるようにします。むしろ、foo3文字のシーケンスに割り当てることをお勧めします5 + 6

foo したがって、..文字列ではなく数値として処理されることをBashに通知する方法が必要です。これは明示的な機能がdeclare 便利な場所です。

言う:

declare -i foo=5+6  # <<- note the '-i' option: it means 'integer'

Bashが喜んであなたのために計算をして割り当てます。数字変数の値は11ですfoo

つまり、変数をdeclare -i foo提供すると言うことでfooプロパティ整数です。

数字(Bashはまだ小数点、浮動小数点数などを理解していないため、正確な整数)を宣言することがおそらくを使用する最初の理由ですdeclare。しかし、それが唯一の理由ではありません。すでに知っているように、変数に他のプロパティを割り当てることもできます。たとえば、Bashに何があっても常に変数の値を大文字で表示するように指示できます。と言えば、declare -u fooその時点からfoo=barBashが実際に文字列をBAR変数に割り当てると言えますfoo

これらの属性を変数に割り当てるには〜しなければならないコマンドを使用してくださいdeclare。他のオプションはありません。


これで提供できるもう1つの属性declareは、悪名高い「name-ref」属性である-n属性です。 (今は以前に消しておいたコンセプトを再び生かしたいです。)。

デフォルトでは、name-ref属性はBashプログラマーが変数の値を変更する別の方法を可能にします。より正確に教える間接的なこれを行う方法。

これはどのように効果があります:

あなたは次のdeclare属性を持つ変数です。-n非常に値も指定することをお勧めします(厳密には必須ではありませんが、操作が簡単になります)。これ同じdeclareコマンドにもさまざまなバリエーションがあります。このように:

declare -n baz="foo"

これは、Bashに、それ以降、名前付き変数の値を使用または変更するたびに、名前付き変数bazの値を実際に使用または変更する必要があることを伝えますfoo

これは、その時点からbaz=10+3make fooget the value 13のようなコマンドを発行できることを意味します。もちろん、foo以前に整数(declare -i)として宣言されたと仮定すると、そうでなければ4つの文字シーケンスが得られます1 0 + 3

fooまた、 のように値を直接変更するとfoo=15say として 15 も表示されますecho “${baz}”。これはbaz、name-refとして宣言された変数がfoo常にfoo値を反映しているためです。

上記のdeclare -nコマンドは変数を作成するため、「名前参照」と呼ばれます。baz 引用する到着名前もう一つの変数です。実際、私たちはこのオプションのおかげで、Bashで別の変数名として扱われるbaz 「foo」値として宣言しました。-n

今、なぜ地球でこのようなことをしたいですか?

まあ..これはかなり高度な要件を満たす機能であることは言及する価値があります。

実際には、プログラマが実際に名前参照を必要とする問題に直面したとき、そのような問題を解決するために、Bashではなく適切なプログラミング言語を使用する必要があるほど進歩しました。

たとえば、これらの高いレベルの要件の1つは、プログラマとして開発中に不明な場合です。どのスクリプトの特定のポイントで変数を使用する必要がありますが、〜する実行時に動的に完全に理解されます。プログラマが実行時に介入できないことを考慮すると、唯一のオプションはプロビジョニングを作成することです。 前進スクリプトのこのような状況では、おそらく "name-ref"が唯一の方法です。これらの高度な要件に対するよく知られたユースケースとしてプラグインを検討してください。 「プラグイン」プログラムのプログラマーは、将来(およびおそらく第三者)プラグインの一般規定を事前に作成する必要があります。したがって、プログラマはBashでname-refなどのツールを使用する必要があります。

もう1つの高度な要件は、大量のデータを処理する必要がある場合です。記憶の中でまた、スクリプト関数にそのデータを渡す必要があります。返品このデータは途中で変更する必要があります。この場合はもちろん可能です。コピーデータはある関数から別の関数に転送されますが(Bashのようにまたはからのようなdest_var="${src_var}"関数を呼び出すときmyfunc "${src_var}")、データが大きくなり、膨大なRAMの無駄が発生します。そして非常に非効率的な作業です。したがって、このような状況が発生した場合、解決策はデータのコピーを使用するのではなく、引用するこのデータに。 Bashでは名前が引用されます。このユースケースは実際にはすべての現代のプログラミング言語の標準ですが、Bashでは非常に例外的です。 Bashは主にファイルと外部コマンドを主に処理する短くて簡単なスクリプト用に設計されているため、Bashスクリプトは膨大な量のコードを渡す必要が非常に少なくなります。関数間データ。スクリプトの機能が一部のデータを共有する必要がある場合(アクセスと変更)、これは通常、Bashスクリプトでよく使用されるグローバル変数を使用して簡単に達成できます。非常にそのプログラミング言語では廃止されました。

その場合、Bashの名前参照に対する注目すべきユースケースがあるでしょう。そして(おそらく皮肉なことに)これは他の種類の変数を扱うときに関連しています。

  1. 「インデックス配列」として宣言された変数(declare -a
  2. 「連想配列」()で宣言された変数declare -A

これは次の変数クラスです。簡単に(そしてより効率的に)多くのデータを渡さなくても、通常のコピーではなく名前参照を使用して関数を渡します。

これらの例のすべてが奇妙に聞こえ、まだ理解しにくい場合は、名前参照が実際に高度なトピックであり、Bashの一般的な使用シナリオにはほとんど必要ありません。

Bashで名前参照の用途を見つけたいくつかの状況を説明することができますが、これまではほとんどかなり「比較的」、複雑な要件に使用されていました。学習中です。この段階では、状況が複雑になる可能性があります。最も複雑ではない(おそらく深刻ではない)ことを言及する場合は、関数から値を返すことです。 Bashは実際にこれをサポートしていないので、name-refを使って同じ機能を得ました。さて、これはサンプルコードが何をするのかです。


それ以外にも、実際にコメントに適している小さな個人的な提案がありますが、StackExchangeコメントの制限に合うように十分に圧縮することはできません。

私の考えでは最大今やるべきことは、私が示した簡単な例と提供されたサンプルコードを使ってname-refを試すことです。今は「正確になぜ」部分を無視し、「動作方式」部分にのみ少しの実験を加えることです。 、「どのように」部分「部分が心によりよく位置付けられる可能性があるため、「なぜ」部分は、適切なプロセスで実際の実際の問題に直面するとき(または場合)、その名前が — — 審判が出た場合に明確になります。 。

答え4

Declareは、Bashで変数を宣言するいくつかの構文の1つです。

x=7
declare x=7
declare x

function something {
  local x
  local x=7
}

変数を宣言するこれらのさまざまな方法は、シェルが徐々に進化した結果です。

これは-n時々「変数」と呼ばれることを宣言する方法です。これは他の変数にバインドされた変数です。次のスクリプトをテストできます。オンライン:

#!/bin/bash
set -o errexit -o nounset -o pipefail

declare thevariable
declare -n thevariablevariable=thevariable

thevariable='the value'

printf 'thevariable: %s\n' "$thevariable"
printf 'thevariablevariable: %s\n' "$thevariablevariable"

thevariablevariable='the other value'

printf 'thevariable: %s\n' "$thevariable"
printf 'thevariablevariable: %s\n' "$thevariablevariable"

これを実行すると、へのthevariablevariableポインタthevariableではなくエイリアスが表示されますthevariable

thevariable: the value
thevariablevariable: the value
thevariable: the other value
thevariablevariable: the other value

さて、これは狡猾なバグ機能のように見えるかもしれませんが、実際には珍しい言語機能です。しかし、シェルプログラミングには時々奇妙な機能が必要です。

シェルは理論的には非常に単純でLofi言語なので、シェルで変数を宣言する方法が多すぎるのは奇妙に見えますが、これはプログラムの進歩的な変化に関連しています。例は関数ローカル変数の定義です。

値を設定する最も簡単な方法は明らかですx=7。しかし、関数を持つスクリプトがある場合、次のことはどういう意味ですか?

#!/bin/bash
set -o errexit -o nounset -o pipefail

x=7

function something {
  x=6
}

something

printf 'What is x? It is: %s\n' "$x"

まあ、1つの合理的な説明は、xまだスクリプトの最後にある必要があるということです7。しかし、実際には6です。なぜなら、関数宣言がローカルであることがプログラマの間で一般的な期待ではなかった時があったからです。経験によると、ローカル関数は良い習慣ですが、シェルで宣言の意味を単純に変更することはできません。これはすべての古いスクリプトが破損するためです。したがって、新しい宣言構文を導入します。

関連情報