この質問に対するilkkachuの回答を読んだ後私はdeclare
(引数-n
)シェルが組み込まれています。
help declare
もたらすもの:
変数の値と属性を設定します。
変数を宣言し、属性を指定します。NAMEが指定されていない場合は、すべての変数の属性と値。
-n … NAMEをその値で指定された変数への参照にします
I man
がわからないので、declare
に関する例を挙げて一般的な説明を求めてください。変数とは何かを知っていて、それを展開していますが、declare
(変数属性?)のman
がありません。
多分あなたは答えの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 }
コメント
- 関連: unix.stackexchange.com/questions/522366/ …
回答
ほとんどの場合、bash
asdf="some text"
ただし、変数の値を整数のみにしたい場合があります(したがって、後で自動的に変更される場合でも、次のようにしか変更できません。整数、場合によってはデフォルトでゼロ)、次を使用できます:
declare -i num
または
declare -i num=15
配列が必要な場合があり、declare
declare -a asdf # indexed type
または
bash
で、検索文字列「bash arraytutorial」(引用符なし)を使用してインターネットを閲覧すると、配列に関する優れたチュートリアルが見つかります。例
linuxconfig.org/how-to-use-arrays-in-bash-script
これらは変数を宣言するときに最も一般的なケースだと思います。
関数内のivid = “0dc7e3df43″にも注意してください
- >
は変数を(関数内で)ローカルにします
名前なしで、すべての変数を(アクティブシェル内で)一覧表示します
declare
最後に、iv id = “のシェル組み込みコマンドdeclare
の機能の概要を取得します。 c97b0c7f5a “> コマンドを使用
help declare
コメント
- OPからこんにちは!私はあなたの答えが素晴らしいと思います、そして私はそれを賛成しました、そして私の意見では、これに感謝します、非常に教訓的な答え。私の謙虚な意見では、初心者が読みやすくするためのマイナーな編集を提案しました。その提案を確認してください。
-
user:muru
が編集を拒否することに投票したのを見ました。私とムルは、このウェブサイトのさまざまなセクションで”が何度か”衝突しており、彼の拒否は目的であり、ここの編集提案ページに表示される直接の変更とは対照的に、実際には有害です: unix.stackexchange.com/review/suggested -edits / 325749 - @JohnDoea、別のユーザーもあなたの編集を拒否しているのを見ました。あなたの編集のいくつかは良いと思いますが、それらのいくつかは私が意図したものからメッセージを変えるので、私はそれらを望まないでしょう。答えを編集して、良い編集だと思うものを含めることができます。
- ありがとうございます;ご存知かもしれませんが、SEでは編集を拒否する方が(部分的にでも)受け入れるよりもはるかに一般的です。別のユーザーが編集を拒否したことを知らせてくれて(’正直に前に見ていませんでした)、私の編集の少なくとも一部をあなたの回答に挿入することを検討していただきありがとうございます。私はこれをとても尊敬しています。
回答
help declare
はかなり簡潔です。より明確な説明は、man bash
またはinfo bash
にあります。後者が以下のソースです。
まず、いくつかの定義。 変数と属性について:
パラメータは値を格納するエンティティ。 … 変数は、
name
で示されるパラメーターです。変数には、値と0個以上の属性があります。属性は、declare
組み込みコマンドを使用して割り当てられます…
そしてdeclare
組み込み aについて>:
declare
declare [-aAfFgilnrtux] [-p] [name[=value] …]
変数を宣言し、属性を指定します。名前が指定されていない場合は、代わりに変数の値を表示します。
…
-n
それぞれに name nameref 属性。これにより、別の変数への名前参照になります。その他の変数は、 name の値によって定義されます。-n
属性自体を使用または変更する場合を除き、 name へのすべての参照、割り当て、および属性の変更は、によって参照される変数に対して実行されます。名前の値。 …
名前参照変数はBash4.3以降でのみ使用可能であることに注意してください 1 。
また、declare
とBashの変数属性の便利な紹介として、を紹介します。 “への回答 declare name
とdeclare -g
は何をしますか? “(ただし、主に変数のスコープに焦点を当てています)。
基本的に 2 、declare name=[value]
は、おそらくおなじみの割り当てname=[value]
と同等です。どちらの場合も、name
にはnullが割り当てられます。 value
が欠落している場合の値。
わずかに異なるdeclare name
は、代わりに設定されないことに注意してください。 変数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
は次のようになります。
- 宣言 unset 、
declare name
; - 宣言および set の後に em> null を値として、
name=
またはdeclare name=
; - 宣言、 set 、および
name=value
またはivid = “6810b6addの後に non null 値を指定9 “>
。
より一般的には、declare [options] name=value
- 変数
—これは名前の付いたパラメータであり、情報を格納するために使用できるメモリの一部にすぎません 4 ; - 割り当て値
value
をそれに; - オプションで
name
の属性を設定します。これにより、値の両方の種類が定義されます。格納できる(タイプではなく、厳密に言えば、Bashの言語はタイプされていないため)、およびその操作方法。
属性は例を使用すると、おそらく簡単に説明できます。declare -i name
を使用すると、” integer “属性が設定されます。 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のコードで起こっていることは、次のとおりです。
-
ref
という名前の変数がnameref “属性セット、および $1
のコンテンツ(最初の位置引数)がに割り当てられますit:declare -n ref="$1"
は、別の変数の名前を保持するためのものです。これは、動的に定義する必要があるため(たとえば、コードの一部を再利用して取得するため)、通常は事前にはわかりません。いくつかの変数に適用されます)、およびそれを参照(および操作)するための便利な方法を提供します。 (ただし、1つだけではありません。間接参照が代替手段です。シェルパラメータの拡張を参照してください。) -
いつ変数
tmp1
の値はref
に割り当てられます:ref=$tmp1
名前が
ref
の値である追加の変数が暗黙的に宣言されます。tmp1
の値も、ref
へのこの明示的な割り当てによって、暗黙的に宣言された変数に間接的に割り当てられます。 。
リンクされた質問のコンテキストで、read_and_verify
as
read_and_verify domain "Prompt text here..."
変数そしてそれに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(現在は最新バージョン)はBash4.2に同梱されています。
2 通常どおりシェルビルトイン、徹底的な 簡潔な説明は、さまざまな、場合によっては異種のアクションを実行するため、とらえどころのないものです。属性の宣言、割り当て、設定のみに焦点を当て、属性の一覧表示、スコープ設定、削除はこの回答の範囲外と見なします。
3 declare -p
のこの動作は、Bash4.4で導入されました。参照:変更ファイル、セクション” 3。 Bashの新機能”、ポイント” f “。
As G-Man 、Bash 4.3 declare name; declare -p name
ではエラーが発生します。ただし、declare -p | grep "declare -- name"
でname
が存在することを確認できます。
4 FullBashGuide、mywiki.wooledge.orgの パラメータ
コメント
- (1)最初のコードブロックに表示された結果を再現できません:
declare name
の後にdeclare -p name
は、「bash:declare:name:notfound」を生成します。 (declare -p | grep na
はdeclare -- name
を生成しますが。)(2)echo "${name-isunset}"
declare name
のコンテキストでは、宣言されていない(つまり、未定義の)変数を宣言されたと同じように扱います。 i>が未設定変数。 (3)namerefはbashバージョン4.3以降でのみ使用可能であることに言及することをお勧めします。 - @ G-Manご意見ありがとうございます。 ‘できるだけ早く対処し、’必要に応じて回答を更新します。 (1)に関しては、ArchLinuxでの
GNU bash, version 5.0.7(1)-release (x86_64-pc-linux-gnu)
でも、表示した結果が得られます。その動作が導入されたのはごく最近のことかもしれませんが、’調査します。 - そうです。 ‘バージョン4.3のみを使用しています。
- @ G-Man Answerが更新され、(1)と(3)に関するメモが追加されました。 (2)について:
declare x
が’を設定しないことを説明することを目的としましたx
、declare x=
はそうです。 ‘declare -- x
(declare -p x
)は”が設定されていないことを意味します”、declare -- x=""
は set “;したがって、” unset “を区別できない場合でも、${parameter-word}
拡張を導入しました。ご指摘のとおり、”は’存在しません”。 ‘ただし、(読者の注意をそらすことなく)回答でこれを明確にするにはどうすればよいかわかりません。
回答
これについて説明しますが、提供された例に従わない場合はご容赦ください。むしろ、私自身の異なるアプローチに沿ってガイドしようと思います。
「変数」や「それらの拡張」などの概念をすでに理解しているとおっしゃっていますので、いくつかをざっと見ていきます。さもなければより深い焦点を必要とするであろう背景知識。
それで、私は、せいぜい基本的なレベルでは、declare
コマンドは、変数値(つまり、スクリプトの実行中に変更される可能性のある値)が必要であることをBashに伝えるための単なる方法です。特定の名前、正確にはdeclare
コマンド自体の横に指定した名前を使用してその値を参照します。
つまり:
declare foo="bar"
Bashにあなたに伝えますfoo
という名前の変数の値がbar
である必要があります。
しかし、ちょっと待ってください。 declare
をまったく使用せずにそれを行うことはできません。例:
foo="bar"
非常に正しい。
そうですね。 、上記の単純な割り当ては、実際には暗黙の方法です。実際には..変数を宣言します。
(また、上記が の
change foo
という名前の変数の値。実際、これは正確に最も直接的なものです。簡潔で、明白で、率直な方法です。しかし、それだけではありません。..後でこれに戻ります。)。
しかし、そうであれば。 declare
をまったく使用せずに、「変数値にタグを付ける名前」(簡潔にするために、以降は「変数」のみ)を宣言することは可能ですが、なぜそうする必要があるのでしょうか。この豪華な「declare」コマンドを使用しますか?
答えは、上記の暗黙の事実にあります変数を宣言する方法(foo="bar"
)、それは..暗黙的に..Bashに、シェルの一般的な使用シナリオで最も一般的に使用されるタイプの変数を考慮させます。 。
このような型は文字列型、つまり特定の意味を持たない文字のシーケンスです。したがって、暗黙の宣言を使用すると文字列が得られます。
しかし、プログラマーとして、変数を、たとえば、算術演算を行う必要のある数値と見なす必要がある場合があります。操作..そしてfoo=5+6
のような暗黙の宣言を使用しても Bashは値11をfoo
に割り当てません。あなたが期待するかもしれません。むしろ、foo
に3文字のシーケンス5
+
。
つまり、foo
を数値ではなく数値と見なすことをBashに伝える方法が必要です。文字列..これが、明示的なdeclare
が役立つ理由です。
次のように言ってください:
declare -i foo=5+6 # <<- note the "-i" option: it means "integer"
そしてBashが喜んで計算を行い、数値値11を変数。
つまり、declare -i foo
と言うと、変数foo
foo
em>整数であるという属性。
数値を宣言すること(Bashはまだ小数や浮動小数点などを理解していないため、正確には整数)が
ですが、それだけが理由ではありません。すでに理解しているように、変数に与えることができる属性は他にもいくつかあります。たとえば、Bashを使用して、変数の値を常に大文字にすることができます。declare -u foo
と言うと、それ以降、foo=bar
Bashは、実際には文字列BAR
を変数foo
に割り当てます。
これらの属性のいずれかを与えるために変数に対しては、declare
コマンドを使用する必要があります。他に選択肢はありません。
これで、もう1つdeclare
を介して指定できる属性は、悪名高い「name-ref」属性である-n
属性です。 (そして今、私は以前に保留にした概念を再開します)。
name-ref属性は、基本的に、Bashプログラマーが値を変更する別の方法を可能にします。変数の。より正確には、それを行うための間接的な方法を提供します。
ここに方法動作します:
declare
が-n
属性を持つ変数であり、それは非常にお勧めします(厳密には必須ではありませんが、作業が簡単になります)。同じdeclare
の this 非常に変数にも値を指定することをお勧めします。 div>コマンド。次のようになります。
declare -n baz="foo"
これにより、Bashにそのことを通知します。 onで、baz
という名前の変数の値を使用または変更するたびに、。
つまり、それ以降は、 baz=10+3
のように言うと、foo
の値は13になります。もちろん、foo
が1分前と同じように以前に整数(declare -i
)として宣言されていたとすると、そうでない場合はシーケンスが取得されます。 4文字のうち1
0
+
3
。
また、foo=15
のように、foo
の値を直接変更すると、次のように表示されます。 15 echo “${baz}”
とも言います。これは、foo
のname-refとして宣言された変数baz
が常にfoo
を反映しているためです。値。
上記のdeclare -n
コマンドは、変数baz
別の変数の名前を参照します。実際、baz
の値は “foo”であると宣言しました。これは、-n
オプションがあるため、Bashによって名前として処理されます。別の変数。
さて、なぜ地球上でしたいのですか?
まあ..これは非常に高度なニーズのための機能であると言う価値があります。
実際、プログラマーが本当に名前参照を必要とする問題に直面した場合、それはまた非常に高度です。このような問題は、Bashの代わりに適切なプログラミング言語を使用して対処する必要がある可能性があります。
これらの高度なニーズの1つは、たとえば、プログラマーとして開発中に知ることができない場合です。スクリプトの特定のポイントで使用する必要がある変数ですが、実行時に動的に完全に認識されます。 また、実行時にプログラマーが介入する方法がないことを考えると、唯一のオプションは、スクリプトでそのような状況に備えて事前にプロビジョニングすることであり、「name-ref」が唯一の実行可能です。仕方。この高度なニーズの広く知られているユースケースとして、たとえばプラグインを考えてみてください。 「プラグイン可能な」プログラムのプログラマーは、将来の(場合によってはサードパーティの)プラグインの一般的なプロビジョニングを事前に行う必要があります。したがって、プログラマーはBashのname-refなどの機能を使用する必要があります。
もう1つの高度なニーズは、RAM内の大量のデータを処理する必要がある場合です。 スクリプトの関数にそのデータを渡す必要があります。またその途中でそのデータを変更する必要があります。このような場合、そのデータをある関数から別の関数にコピーすることができます(dest_var="${src_var}"
を実行するときや
次に、Bashでの名前参照の注目すべき使用例があり、(皮肉なことに)さらに他のタイプの変数を使用する場合に関連付けられます。
- 「インデックス付き配列」として宣言されている変数(
declare -a
) - 「連想配列」として宣言されている変数(
declare -A
)。
これらは、関数に渡されるより簡単な(そしてより効率的な)変数のタイプです。大量のデータを運ばない場合でも、通常のコピーではなく名前参照を使用する。
これらすべての例が奇妙に聞こえ、それでも理解できない場合、それは名前参照が実際に高度なトピック、およびBの典型的な使用シナリオのまれな必要性ash。
Bashで名前参照が使用されていることがわかった場合についてはお話しできますが、これまでのところ、ほとんどの場合、非常に「難解」で複雑なニーズに対応してきました。私がそれらを説明した場合、私はあなたの学習のこの時点であなたのために物事を複雑にするだけだろうと恐れています。最も複雑でない(そしておそらく難解ではない)ことに言及するだけです:関数から値を返します。 Bashは実際にはこの機能をサポートしていないので、name-refsを使用して同じ機能を取得しました。ちなみに、これはサンプルコードが行うこととまったく同じです。
これに加えて、コメントに適した小さな個人的なアドバイスですが、十分に要約することはできませんでした。 StackExchangeのコメントの制限に収まるように。
現時点で最もすべきことは、私が示した簡単な例と、おそらく提供したサンプルコードを使用して、名前参照を実験することだと思います。今のところ、「なぜ地球上にあるのか」の部分と「それがどのように機能するのか」の部分だけに焦点を当てています。少し実験することで、「どのように」の部分が頭に浮かぶかもしれません。その結果、「なぜ」の部分は、名前が実際に問題になるとき(または問題がある場合)に、やがて明らかになります。 refは本当に便利です。
コメント
- LL3私はあなたの答えがとても好きで、私は親指を立てました:私はついに宣言が何をするのか理解しました- -変数を宣言するのではなく、それらの属性を宣言します。それでも悲しいことに、あなたが名前参照とは何かを説明し始めたとき、私は道に迷いました。それが何をするのか、なぜそれを使うのか分かりませんでした。
- つまり、なぜこの属性を与えるのでしょうか
- @JohnDoeaなるほど。たぶん、あなたは今のところこのトピックを残すかもしれません。学習の現時点でこの概念を理解するのはおそらく時期尚早です。とにかく、私はより多くの例と、あなたがどのように進めるべきだと思うかについての少し個人的な補遺で私の答えを拡大しました。また、個人的な補遺の
-n
の具体的な説明から、declare
の一般的な説明を区切るために横線を引いています。また、あちこちで少し言い換えましたが、実質的なことは何もないので、-n
の部分と小さな補遺をもう一度読んでください。 - ありがとうございます。’今すぐこれについて学んでも大丈夫だと思います。理解できる説明が必要です。今日は回答全体を読み直してください。 ‘ここにいます。
-
foo="bar"
とdeclare foo="bar"
について言及しています。シェル関数で、declare foo="bar"
がローカル変数を作成し、foo="bar"
がローカル変数を作成することを(脚注でのみ)言及することをお勧めします。グローバル変数。
回答
一般的に、declare
bash
シェルは、変数の属性を設定(または削除または表示)します。属性は、「これは名前の参照です」、「これは連想配列です」、「この変数は常に整数として評価する必要があります」、「この変数は読み取り専用であり、できません」という注釈の一種です。リセットする」、「この変数はエクスポートされます(環境変数)」など。
typeset
ビルトインはividの同義語です。 bash
の= “0dc7e3df43”>
は、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 Please enter value for "foo": hello Please repeat the value to verify: hello? Values unmatched. Please try again. The variable "foo" has the value ""
これは、ユーザーが2つの異なるを入力したときに、foo
変数が何にも設定されていないことを示しています。 文字列。
これは、変数foo
が、ユーザーが同じ文字列を2回入力したときに入力した文字列に設定されることを示しています。 。
スクリプトの主要部分で$foo
が値hello
を取得する方法は次のとおりです。シェル関数内:
declare -n ref="$1" ref=$tmp1
ここで、$tmp1
は文字列hello
はユーザーが入力し、$1
は、関数のコマンドラインでメイン部分から渡される文字列foo
です。スクリプト。
ref
変数が名前参照変数としてdeclare -n
で宣言されており、値がfoo
は、その宣言の値として指定されます。つまり、その時点から、変数がスコープ外に出るまで、変数ref
の使用はfoo
。変数ref
は、この時点でfoo
を参照する名前参照変数です。
これにより、宣言の次の行で行われているように、ref
に値を割り当てると、その値がfoo
に割り当てられます。
値hello
は、スクリプトの主要部分の$foo
で使用できます。