Help us understand the problem. What is going on with this article?

Bash 5.0の新機能:localvar_inherit

More than 1 year has passed since last update.

Bash 5.0のNEWSファイルをさくっと翻訳したエントリー「bash 5.0のNEWSファイル私訳」を先日書きました。

この中に、localvar_inheritという新しいshoptオプションが追加されたことが書かれています。

o. 新しいshoptオプション:localvar_inherit。設定すると、ローカル変数
   は、直前のスコープにある同じ名前の変数の値を継承します。

自分で訳しておいてなんですが、わかりにくいですね。

Bash 5.0のmanpageでは、こう説明されています。

localvar_inherit
        If set, local variables inherit the value and attributes
        of a variable of the same name that exists at a previous
        scope before any new value  is  assigned.   The  nameref
        attribute is not inherited.

やはりわかりにくいですね。

そこで、ちょこっと調べて試してみた結果を、順を追って説明します。

おさらい①:関数

多くのプログラミング言語と同じく、Bashでも関数を定義できます。定義した関数はコマンドとして実行できます。

$ cat hello.sh
hello() {               # helloという関数を定義
    echo hello
}

hello                   # helloを実行
$ bash ./hello.sh
hello

おさらい②:ローカル変数

単純なシェルでは変数はグローバル変数しかありません。しかしBashでは、localコマンドによって関数内のローカル変数を定義できます。

$ cat localvar.sh
foo() {
  local aaa     # aaaというローカル変数を定義
  aaa=5         # aaaに5を代入
}

aaa=3           # aaaに3を代入
foo             # fooを実行
echo $aaa       # その後でaaaの値は?
$ bash ./localvar.sh
3

おさらい③:ローカル変数はダイナミックスコープ

Bashのローカル変数のスコープは、呼び出し先の関数でも有効です。Common Lispのスペシャル変数や、Emacs Lispのデフォルトのダイナミックスコープ変数、Perlのlocalなどに似ています。

次のように、関数fooと、fooから呼び出す関数barを定義します。すると、fooで定義したローカル変数aaaがbarからも参照できます。

$ cat scope.sh
foo() {
  local aaa=3   # aaaというローカル変数を定義して値を3に
  bar
}

bar() {
  echo $aaa     # barでのaaaの値は?
}

foo
$ bash ./scope.sh
3

同じ変数aaaを参照しているので、barで値を変更すると、fooでも変更されています。

$ cat scope2.sh
foo() {
  local aaa=3   # aaaというローカル変数を定義して値を3に
  bar
  echo $aaa     # barを呼び出した後でaaaの値は?
}

bar() {
  aaa=5         # barでaaaに5を代入
}

foo
$ bash ./scope2.sh
5

ようやく本題:localvar_inherit

では、Bash 5.0の新機能であるlocalvar_inheritを見てみましょう。

localvar_inheritをオンにすると、呼び出し元の変数と同じ名前の変数をlocalで定義したときに、呼び出し元の変数の値と属性が コピー されます。

次の例では、fooとbarで同じ名前の変数aaaを定義しています。barではaaaの値を代入していないのに、fooでaaaに設定した値が参照されます。

$ cat inherit.sh
shopt -s localvar_inherit       # localvar_inheritをオンに

foo() {
  local aaa=3   # fooでローカル変数aaaを定義
  bar
}

bar() {
  local aaa     # barでもaaaを定義。値は代入しない
  echo $aaa     # aaaの値は?
}

foo
$ bash ./inherit.sh
3

ダイナミックスコープと違い、同じ変数を参照するわけではありません。次のように、barでaaaの値を変更しても、fooのaaaの値は変わりません。

$ cat inherit.sh
shopt -s localvar_inherit

foo() {
  local aaa=3
  bar
  echo $aaa     # barを呼び出した後でaaaの値は?
}

bar() {
  local aaa
  aaa=5         # barでaaaに5を代入
}

foo
$ bash ./inherit.sh
3

用途

さて、これをどういうところで使うと便利でしょうか。

普通の変数の値であれば、引数などで渡せば十分です。ただし、配列は引数などでは渡しづらいので、localvar_inheritを使って呼び出し先にコピーするのが便利そうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした