web-dev-qa-db-ja.com

バッシュの「宣言」とは何ですか?

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
}
12
user149572

ほとんどの場合、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
4
sudodus

_help declare_の出力はかなり簡潔です。より明確な説明は_man bash_または_info bash_にあります。後者は以下のソースです。

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

parameterは、値を格納するエンティティです。 ... variableは、nameで示されるパラメーターです。変数にはvalueと0個以上のattributesがあります。属性はdeclare組み込みコマンドを使用して割り当てられます...

そして、declarebuiltin について:

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ではないことに注意してください。

_$ 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は次のようになります。

  • declaredおよびnset、_declare name_の後;
  • declaredおよびsetnullを値として、_name=_または_declare name=_の後;
  • declaredsetおよび_name=value_または_declare name=value_の後にnon null値を指定します。

より一般的には、_declare [options] name=value_

  1. 変数nameを作成します—これは名前を持つパラメーターであり、これは情報を格納するために使用できるメモリの一部にすぎません4;
  2. valueをそれに割り当てます。
  3. オプションで、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のコードで起こっていることは次のとおりです。

  1. 「nameref」属性が設定されたrefという名前の変数が宣言され、_$1_(最初の位置引数)の内容がそれに割り当てられます。

    _declare -n ref="$1"
    _

    refなどの名前参照変数の目的は、別の変数の名前を保持することです。これは、動的に定義されるようにするため(たとえば、コードの一部を再利用して、それはいくつかの変数に適用されます)、そしてそれを参照する(そして操作する)ための便利な方法を提供します。 (ただし、唯一のものではありません:インダイレクションは代替手段です Shell Parameter Expansion を参照してください)。

  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参照: [〜#〜] changes [〜#〜] ファイル、セクション「3. Bashの新機能」、ポイント「w」。
これは関連している可能性があります。たとえば、CentOS Linux 7.6(現在の最新バージョン) Bash 4.2に同梱

2シェルのビルトインでいつものように、徹底的なand簡潔な説明は、さまざまな、場合によっては異種のアクションを実行するため、とらえどころのないものです。私は属性の宣言、割り当て、設定のみに焦点を当て、この回答の範囲外として、属性のリスト、スコープ、および削除を検討します。

この_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

13
fra-san

一般に、declareシェルのbashは、変数にattributesを設定(または削除、または表示)します。属性は、「これは名前参照です」、「これは連想配列です」、「この変数は常に整数として評価する必要があります」、または「この変数は読み取り専用であり、再設定する」、「この変数はエクスポートされる(環境変数)」など.

typesetは他のシェル(declareで使用されるため、bashtypesetkshの同義語です発生、および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で使用できます。

6
Kusalananda