Ilkkachuの答えを読んだ後 この質問 組み込みのdeclare
(引数-n
)シェルの存在について学びました。
help declare
がもたらすもの:
変数の値と属性を設定します。
変数を宣言して属性を与えます。 NAMEが指定されていない場合は、すべての変数の属性と値を表示します。
-n ... NAMEをその値で指定された変数への参照にします
declare
が理解できないので、man
に関する例を使って一般的な説明を求めます。変数とは何かを知っていて、それを展開していますが、man
(変数属性?)のdeclare
がまだありません。
たぶんあなたは答えで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
}
ほとんどの場合、bash
での暗黙の宣言で十分です。
asdf="some text"
ただし、場合によっては、変数の値を整数のみにすることもできます(そのため、後で自動的に変更される場合でも、整数にのみ変更でき、場合によってはデフォルトでゼロになります)。
declare -i num
または
declare -i num=15
配列が必要な場合は、declare
が必要になります。
declare -a asdf # indexed type
または
declare -A asdf # associative type
検索文字列 'bash array tutorial'(引用符なし)でインターネットを閲覧すると、bash
に配列に関する適切なチュートリアルがあります。たとえば、
linuxconfig.org/how-to-use-arrays-in-bash-script
変数を宣言する場合、これらが最も一般的なケースだと思います。
それにも注意してください
declare
は変数をローカルにします(関数内)名前なしで、すべての変数をリストします(アクティブなシェル内)
declare
最後に、次のコマンドを使用して、シェル組み込みコマンドdeclare
の機能の概要をbash
に取得します。
help declare
_help declare
_の出力はかなり簡潔です。より明確な説明は_man bash
_または_info bash
_にあります。後者は以下のソースです。
まず、いくつかの定義。 変数と属性 について:
parameterは、値を格納するエンティティです。 ... variableは、
name
で示されるパラメーターです。変数にはvalueと0個以上のattributesがあります。属性はdeclare
組み込みコマンドを使用して割り当てられます...
そして、declare
builtin について:
declare
_declare [-aAfFgilnrtux] [-p] [name[=value] …]
_変数を宣言して属性を与えます。名前が指定されていない場合は、代わりに変数の値を表示します。
...
_
-n
_
各namenameref属性を指定して、別の変数への名前参照にします。他の変数はnameの値によって定義されます。 _-n
_属性自体を使用または変更するものを除き、nameへのすべての参照、割り当て、および属性変更は、nameで参照される変数に対して実行されます値。 ...
name reference変数はBash 4.3以降でのみ使用できることに注意してください1。
また、Bashのdeclare
と変数属性の便利な概要については、 this answer to "What do _declare name
_ and _declare -g
_ do?"(これは主に焦点を当てています)ただし、変数のスコープ)。
基本的に2、_declare name=[value]
_は、おそらくおなじみの割り当て_name=[value]
_と同等です。どちらの場合も、name
がない場合、value
にはnull値が割り当てられます。
わずかに異なる_declare name
_ではなく、set変数name
ではないことに注意してください。3:
_$ 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
_の後にnon null値を指定します。より一般的には、_declare [options] name=value
_
name
を作成します—これは名前を持つパラメーターであり、これは情報を格納するために使用できるメモリの一部にすぎません4;value
をそれに割り当てます。name
の属性を設定します。これは、格納できる値の種類(厳密にはBashの言語が入力されていないためtypeの観点ではありません)と操作方法の両方を定義します。属性はおそらく例で説明する方が簡単です。_declare -i name
_を使用すると、name
の「整数」属性が設定され、整数として扱われます。 manual を引用すると、「変数に値が割り当てられると、算術評価が実行されます」:
_## 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のコードで起こっていることは次のとおりです。
「nameref」属性が設定されたref
という名前の変数が宣言され、_$1
_(最初の位置引数)の内容がそれに割り当てられます。
_declare -n ref="$1"
_
ref
などの名前参照変数の目的は、別の変数の名前を保持することです。これは、動的に定義されるようにするため(たとえば、コードの一部を再利用して、それはいくつかの変数に適用されます)、そしてそれを参照する(そして操作する)ための便利な方法を提供します。 (ただし、唯一のものではありません:インダイレクションは代替手段です Shell Parameter Expansion を参照してください)。
変数_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参照: [〜#〜] changes [〜#〜] ファイル、セクション「3. Bashの新機能」、ポイント「w」。
これは関連している可能性があります。たとえば、CentOS Linux 7.6(現在の最新バージョン) Bash 4.2に同梱 。
2シェルのビルトインでいつものように、徹底的なand簡潔な説明は、さまざまな、場合によっては異種のアクションを実行するため、とらえどころのないものです。私は属性の宣言、割り当て、設定のみに焦点を当て、この回答の範囲外として、属性のリスト、スコープ、および削除を検討します。
3この_declare -p
_の動作は、Bash 4.4で導入されました。参照: [〜#〜] changes [〜#〜] ファイル、セクション「3. Bashの新機能」、ポイント「f」。
As G-Man がコメントで指摘されているように、Bash 4.3では_declare name; declare -p name
_はエラーになります。ただし、_declare -p | grep 'declare -- name'
_を使用してname
が存在することを確認できます。
4FullBashGuide、 パラメータ mywiki.wooledge.org
一般に、declare
シェルのbash
は、変数にattributesを設定(または削除、または表示)します。属性は、「これは名前参照です」、「これは連想配列です」、「この変数は常に整数として評価する必要があります」、または「この変数は読み取り専用であり、再設定する」、「この変数はエクスポートされる(環境変数)」など.
typeset
は他のシェル(declare
で使用されるため、bash
はtypeset
のksh
の同義語です発生、およびzsh
など)変数の属性を設定します。
質問の名前参照の例をさらに詳しく見てみましょう。
表示するシェル関数とそれを使用する追加のコード:
#!/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
}
read_and_verify foo
printf 'The variable "foo" has the value "%s"\n' "$foo"
これを実行する:
$ bash script.sh 「foo」の値を入力してください: こんにちは 確認のために値を繰り返してください: こんにちは? 値が一致していません。もう一度お試しください。 変数「foo」の値は「」 です。
これは、ユーザーが2つのdifferent文字列を入力したときに、foo
変数が何にも設定されていないことを示しています。
$ bash script.sh 「foo」の値を入力してください: こんにちは 確認のために値を繰り返してください: こんにちは 変数「foo」の値は「hello」
これは、変数foo
が、ユーザーがsame文字列を2回入力したときに入力した文字列に設定されることを示しています。
スクリプトの主要部分で$foo
が値hello
を取得する方法は、Shell関数の次の行によるものです。
declare -n ref="$1"
ref=$tmp1
ここで、$tmp1
はユーザーが入力した文字列hello
であり、$1
はスクリプトのメイン部分から関数のコマンドラインで渡された文字列foo
です。
ref
変数はdeclare -n
を名前参照変数として宣言され、値foo
はその宣言の値として指定されていることに注意してください。つまり、その時点から、変数がスコープ外に出るまで、変数ref
の使用はfoo
の使用と同じになります。変数ref
は名前参照変数この時点でfoo
を参照しています。
これは、宣言に続く行で行われるように、ref
に値を割り当てると、foo
に値が割り当てられるという結果になります。
値hello
は、スクリプトのメイン部分の$foo
で使用できます。