ローカル変数を定義するために「local」キーワードをサポートするシェルのリスト

ローカル変数を定義するために「local」キーワードをサポートするシェルのリスト

BashとZshが変数をサポートしていることを知っていますが、local一部のシステムにはPOSIX準拠のシェルしかありません。localPOSIXシェルでは定義されていません。

localその場合は、どのシェルがローカル変数のキーワード定義をサポートしているかを尋ねたいと思います。

編集する:シェルについては、デフォルトの/bin/shシェルを参照してください。

答え1

これはlocalサポートやサポートされていないほど簡単ではありません。構文にはさまざまなバリエーションがあり、1つまたは別の形式のローカルスコープを使用するシェル間で実行される方法もあります。

そのため、誰もが同意できる基準を設定することは困難です。バラよりhttp://austingroupbugs.net/bug_view_page.php?bug_id=767この分野へのPOSIXの努力に感謝します。

ローカルスコープは1980年代初めにkshに最初に追加されました。

関数でローカル変数を宣言する構文は次のとおりですtypeset

function f {
  typeset var=value
  set -o noglob # also local to the function
  ...
}

(関数サポートは後でBourneシェルに追加されましたが、別の構文(f() command)を使用し、kshその構文のサポートも後で追加されました。

AFAIKの組み込み機能は、local1989年にAlmquistシェル(BSD、dash、busybox shで使用)に最初に追加されましたが、ksh大きく異なる動作をしますtypeset。デリバティブはエイリアスをashサポートしていませんが、いつでも手動で定義できます。typesetlocal

エイリアスはそれぞれ1989年と1991年にbashとzshに追加されましたtypesetlocal

ksh88は1990年頃にlocal文書化されていない別名として追加され、typeset1994年にはpdkshとその派生として追加されました。posh(ベースpdksh)削除されました(必要ですが必須ではないtypeset場合はDebianポリシーを厳密に遵守するため)。localtypeset

指定に対するPOSIXの初期反対typesetは次の通りであった。動的範囲指定。したがって、ksh93(David Kornの1993年のksh書き換え)は次のように変更されました。変化のない代わりに範囲指定。また、ksh93では、ksh88とは異なり、Bourne構文ksh()ではなく構文()を使用してfunction f {...}宣言された関数に対してのみローカルスコープが実行され、Aliasingが削除されました。f() {...}local

localしかし、AT&Tのksh93v -betatypesetと最終バージョンは 。この場合との違いは、関数内でのみ呼び出すことができることです。ksh93bashlocaltypesetbashksh2020ではデフォルトで無効になっています。しかし、local/alias Bashモードがコンパイルされていないdeclare場合でもtypeset(まだ静的範囲がありますが)。

yashtypeset(非常に遅く書かれています)(à la ksh88)がありますが、localバージョン2.48(2018年12月)以降はエイリアスとしてのみ使用されました。

@ヒリー(悲しいことに誰ですか?2021年に死亡)は最近POSIXと互換性のあるBourneシェルの子孫を維持するために使用されます。boshlocalローカルスコープ(同様)はバージョン2016-07-06からサポートされていますash

したがって、ある種のローカル変数スコープを使用する今日のBourneのようなシェルは次のようになります。

  • ksh、すべての実装、およびその派生物(ksh88、ksh93、pdkshおよびposh、mksh、OpenBSD shなどの派生物)。
  • ashおよびすべての派生物(NetBSD sh、FreeBSD sh、dash、busybox sh)
  • 強く打つ
  • 扱いにくい
  • ヤッシュ
  • ボッシュ

さまざまなシステムでは、一部のシステム(ほとんど)にshPOSIXが含まれており、他のシステムには含まれていません(Solarisなど)。さまざまなシステムに実装するには、次のものがあります。sh/bin/usr/xpg4/binsh

  • ksh88: ほとんどの SysV 派生商用 Unices (AIX、HP/UX、Solaris1...)
  • bash:ほとんどのGNU / Linuxシステム、Cygwin、macOS
  • ash:デフォルトでは、Debianおよびほとんどの派生製品(Ubuntu、Linux / Mintを含む)では、管理者はこれをbashまたはmkshに変更できます。 NetBSD、FreeBSD、および一部の派生製品(macOSを除く)
  • busybox sh:ほとんどではありませんが、多くの組み込みLinuxシステム
  • pdkshまたは派生物:OpenBSD、MirBSD、Android

今の違いは次のとおりです。

  • typeset(ksh、pdksh、bash、zsh、yash)およびlocal(ksh88、pdksh、bash、zsh、ash、yash 2.48+)。
  • サポートされるオプションのリストです。
  • 静的(ksh93、function f {...}関数内)および動的範囲(他のすべてのシェル)。たとえば、function f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f出力1と。このプロパティがどのように影響するかを2ご覧ください。exportksh93
  • 何でもlocal/typesetちょうど変数を作る地元のashbosh)または変数の新しいインスタンスを作成します(他のシェル)。たとえば、またはv=1; f() { local v; echo "${v:-empty}"; }; f出力かどうか(bash 5.0以降のオプションを参照)。1emptylocalvar_inherit
  • 新しい変数を生成する変数の場合、新しい変数が継承されるかどうかプロパティ(例:)およびexport/または型と親範囲の変数から取得した型。たとえば、export V=1; f() { local V=2; printenv V; }; f印刷するか1どう2かを印刷するかどうかです。
  • この新しい変数に初期値(型に応じてnull、0、空のリストzsh)があるか、最初に設定されていないか。
  • unset Vその変数をローカルスコープの変数にそのままにするのunsetか、それともそのままにするのかシェル最初のレベルの範囲(場合によっては、、mksh)。たとえば、出力するかどうか(bash 5.0以降のオプションを参照)yashbashv=1; f() { local v=2; unset v; echo "$v"; }1localvar_unset
  • for と同じように、exportキーワードであるか、組み込みキーワードであるか、両方であるか、どの条件でキーワードと見なされるかを確認します。
  • forと同様に、export引数が通常のコマンド引数または割り当てられた値に解析されるかどうか(およびどの条件下でも)です。
  • あなたは言うことができますか?地元の親範囲で読み取り専用の変数です。
  • v=value myfunction自体がローカルまたは非ローカルでmyfunction宣言された場所との相互作用。v

それが私が今考えているすべてです。詳細については、上記のAustinグループエラーを確認してください。

シェルのローカル範囲についてオプション(大変わりやすい)、これをサポートするシェルは次のとおりです。

  • ksh88(2つの関数定義構文を使用):デフォルトでは実行されますが、無効にする方法はありません。
  • ash(1989年以降):と同じですlocal -$-パラメータ(保存されているオプションのリスト)をローカルパラメータに設定します。
  • ksh93function f {...}:これは機能に対してのみ実行されます。
  • zsh(1995年から)。そしてsetopt localoptionsemulate -Lシミュレーションモード(および対応するオプションセット)を機能ローカライゼーションに設定することもできます。
  • bash(2016年以降)にlocal -似ていますashが、管理対象オプションにのみ適用され、set管理対象オプションには適用されませんshopt

sh1 SolarisのPOSIXは/usr/xpg4/bin/sh(関数ローカルオプションを含む多くの適合性のバグがありますが)です。/bin/shSolaris 10より前はBourneシェル(ローカルスコープなし)で、Solaris 11以降はksh93です。

答え2

Stéphaneの回答に関する追加情報を取得するには、サブシェルを使用してローカルを取得します。影響。実際のPOSIXシェルにアクセスすることはできませんが、これはbusyboxで機能します。中括弧の代わりに括弧を使用してash関数を宣言します。これにより、関数がサブシェルで実行されます。(){}

func() (
    echo "in func, before declaring: x=$x"
    x=10
    echo "in func, after declaring: x=$x"
)

x=5
echo "before func: x=$x"
func
echo "after func: x=$x"

出力

before func: x=5
in func, before declaring: x=5
in func, after declaring: x=10
after func: x=5

これは、関数がグローバル変数にアクセスでき、関数内で変数を設定してもグローバル変数が変更されないことを示します。私は時々ディレクトリを変更または変更したいときに$IFSこの手法を使用しますcdが、これらの操作がプログラムの残りの部分に影響を与えたくありません。

関連情報