$ 0や$ 1のシェル/環境変数のような変数はありますか?


17

以下のようなシェルの変数があり$0$1$2$?、など

次のコマンドを使用して、シェルおよび環境変数を印刷しようとしました。

set

しかし、これらの変数はリストにありませんでした。

基本的に、これらの変数はシェル/環境変数とはみなされませんよね?(それらを出力する$場合でも、シェル/環境変数の場合と同様に、先頭にを付ける必要があります)


3
位置パラメータは変数ではありません。環境変数export 3に変えることはできません$3。できませんunset 3。を$3使用して新しい値を割り当てることはできません3=val
カズ

回答:


25

変数は、シェルの3つの異なるパラメーターの1つです。

  1. 変数は名前が有効なシェル識別子であるパラメータです。_または文字で始まり、その後に0個以上の文字、数字、または_
  2. 位置パラメータは、番号パラメータであり$1$2...
  3. 特別なパラメータは、すべての単一文字の名前を持って、そして脇から$0、彼らはすべての様々な句読点文字です。

set シェルの変数のみを表示します。

シェル変数のサブセットは環境変数であり、その値はシェルの起動時に環境から継承されるかexport、有効な名前に属性を設定することによって作成されます。


1
($ 1、$ 2 ...ではなく$ *、$ @)のsetすべてのパラメーターzshと、bashおよびboshの関数が表示されることに注意してください。ksh93などの一部のシェルや、シェル変数にマッピングされていない古いバージョンのダッシュ出力env変数。(env 1=foo ksh -c set印刷します1=foo
ステファンシャゼル

11

環境変数と位置パラメータ

$INTEGER変数のタイプについて説明する前に、変数が実際に何であり、環境変数とどのように異なるかを理解する必要があり$INTEGERます。これは、POSIX(Portable Operating System Interface)規格のセクション2.1(強調鉱山)で説明されています。

  1. シェルは、関数(関数定義コマンドを参照)、ビルトイン(特殊なビルトインユーティリティを参照)、実行可能ファイル、またはスクリプトを実行し、引数の名前を1からnの番号が付けられた位置パラメーターとして、コマンドの名前を指定します(または、スクリプト内の関数の場合、スクリプトの名前)番号0の位置パラメーターとして(コマンドの検索と実行を参照)。

対照的に、$HOMEやなどの変数$PATHは環境変数です。それらの定義は、標準のセクション8で説明されています

この章で定義されている環境変数は、複数のユーティリティ、機能、およびアプリケーションの動作に影響します。特定のユーティリティのみに関係する他の環境変数があります。単一のユーティリティにのみ適用される環境変数は、ユーティリティの説明の一部として定義されます。

それらの説明に注目してください。位置パラメータは、コマンドの前に表示されることを意味しますcommand positional_arg_1 positional_arg_2...。それらは、ユーザーが具体的に何をすべきかをコマンドに伝えるために提供されるものです。を実行echo 'Hello' 'World'すると、HelloとのWorld文字列が出力されます。これらは位置パラメータであり、操作するechoものですecho。そして、echo位置パラメータを印刷される文字列として理解するように構築されます(それらがのようなオプションフラグの1つでない限り-n)。別のコマンドでこれを行うHelloと、何を理解していない可能性がありますWorldおそらく数字を期待するからです。位置パラメータは「継承」されないことに注意してください-子プロセスは、子プロセスに明示的に渡されない限り、親の位置パラメータを認識しません。多くの場合、ラッパースクリプトで渡される位置パラメーターが表示されます。コマンドの既存のインスタンスを確認したり、呼び出される実際のコマンドに位置パラメーターを追加したりするスクリプトです。

対照的に、環境変数は複数のプログラムに影響を与えることを意図しています。これらは環境変数です。これらはプログラム自体の外部で設定されるためです(これについては以下で詳しく説明します)。HOMEまたはなどの特定の環境変数PATHは、特定の形式、特定の意味を持ち、各プログラムで同じことを意味します。HOME変数は/usr/bin/find、シェルなどの外部ユーティリティ(およびその結果としてスクリプト)と同じ意味になります-プロセスが実行されるユーザー名のホームディレクトリです。環境変数を使用して、たとえば特定のコマンドの動作を説明できることに注意してください。UID環境変数を使用して、スクリプトがルート権限で実行されているかどうかを確認し、それに応じて特定のアクションに分岐できます。環境変数は継承可能です-子プロセスは親の環境のコピーを取得します。参照してくださいプロセスは親の環境を継承する場合は、なぜ我々は、エクスポートする必要がありますか?

要するに、主な違いは、環境変数はコマンドの外部で設定され、(通常)変更されることを意図していないのに対し、位置パラメーターはコマンドによって処理され、変更されることを意味することです。


シェルの概念だけではありません

コメントから私が気づいたのは、端末とシェルを混同しているということです。昔は物理的なデバイスだった実際の端末について読むことを本当にお勧めします。今日、私たちが通常参照している「端末」は、黒い背景と緑色のテキストのウィンドウは、実際にはソフトウェアであり、プロセスです。ターミナルはシェルを実行するプログラムであり、シェルもプログラムですが、実行するために入力した内容を読み取ります(つまり、対話型シェルの場合、非対話型シェルはスクリプトおよびsh -c 'echo foo'呼び出しのタイプです)。シェルの詳細はこちら

これは重要な違いですが、端末がプログラムであり、したがって環境と位置パラメータの同じ規則を遵守していることを認識することも重要です。あなたのgnome-terminalあなたを見ていきます始めSHELL、環境変数、およびあなたが持ついくつかの他のコマンドを指定しない限り、あなたのための適切なデフォルトのシェルを起動-e。デフォルトのシェルをksh -gnome-terminalがのksh代わりにスポーンするように変更したとしましょうbash。これは、プログラムが環境を使用する方法の例でもあります。私は明示的に言う場合gnome-terminal-e、特定のシェルを実行する-それはそれを行うだろうが、それは永久的ではありません。対照的に、環境はほとんど変更されないことを意味します(これについては後で説明します)。

ご覧のとおり、環境変数と位置変数は、シェルだけでなくプロセス/コマンドのプロパティです。シェルスクリプトに関しては、Cプログラミング言語によって設定されたモデルに従います。main通常、次のようなC 関数を例にとります。

int main(int argc, char **argv)

、ここで argcはコマンドライン引数の数であり、コマンドargvラインパラメータの配列であり、ユーザーのホームディレクトリパス、実行可能ファイルを検索できるディレクトリのリストなどにアクセスするenviron機能(Linuxの場合man -e 7 environ)がありますPATH。シェルスクリプトも同様の方法でモデル化されます。シェル用語では、位置パラメータ$1などが$2あり$#、位置パラメータの数もあります。どう$0?これも実行可能ファイル自体の名前であり、これもCプログラミング言語からモデル化されています。これはargv[0]Cの「実行可能ファイル」の名前になります。そして、これはほとんどのプログラミングおよびスクリプト言語にかなり当てはまります

対話型シェルと非対話型シェル

既に示唆したことの1つは、対話型シェルと非対話型シェルの違いです。コマンドを入力するプロンプト-対話式で、ユーザーと対話します。対照的に、シェルスクリプトがある場合、または実行bash -c''する場合は非対話的です。

そして、ここで区別が重要になります。すでに実行しているシェルはプロセスであり、位置パラメータで生成されます(bashログインシェルの場合は、「...引数ゼロの最初の文字が-であるか、または--loginオプションで開始されたものです。」(参照) )

対照的に、-coptionで起動されたスクリプトとシェルは$1$2引数を利用できます。例えば、

$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
  File: '/etc/passwd'
  Size: 2913        Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 6035604     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
 Birth: -

オプションのsh小さな癖は、通常はプログラムの名前であるのとは異なり、-c最初の定位置パラメーターを取得してに割り当てることなので、ここでも使用していることに注意してください$0

注目すべき重要な別のことは、位置パラメータが私が「フレーム化可能」と呼ぶものであるということです。最初にbash独自の位置パラメータを使用して起動しましたが、これらの位置パラメータはおよびへのパラメータにechoなりましたstat。そして、各プログラムはそれを独自の方法で理解します。我々はに与えた場合はstat、文字列Hello Worldと何のファイルがありませんHello World、それはエラーを生成するには、bash単純な文字列として扱いますが、statその文字列は既存のファイル名であると想定しています。対照的に、すべてのプログラムは、環境変数HOMEがディレクトリであることに同意します(プログラマーが不合理な方法でコーディングしない限り)。


環境変数と位置パラメータをいじることはできますか?

技術的には、両方を混乱させることはできますが、環境変数を混乱させるべきではありませんが、しばしば位置パラメータを提供する必要があります。たとえば、変数を先頭に追加してシェルでコマンドを実行できます。

$ hello=world bash -c 'echo $hello'
world

export variable=valueシェルまたはスクリプト内から単純に使用して、変数を環境に配置することもできます。または、を使用して完全に空の環境でコマンドを実行できますenv -c command arg1 arg2。ただし、通常は、特に大文字の変数を使用したり、既存の環境変数を上書きしたりして、環境をいじることは推奨されません。これは標準ではありませんが推奨されます。

位置パラメータの場合、それらを設定する方法は明らかで、コマンドの先頭に追加するだけでなく、コマンドを使用してそれらのパラメータのリストを変更するだけでなく、他の方法で設定する方法もありますshift

結論として、これら2つの目的は異なり、それらには理由があります。この回答から人々がある程度の洞察を得てくれることを願っています。この回答を書くのが私にとってそうであったように、それを読むのは楽しかったです。


setコマンドに関する注意

setコマンド、これ等手動挙動に応じて(bashのマニュアルから、強調追加):

オプションがない場合、各シェル変数の名前と値は、現在設定されている変数を設定またはリセットするための入力として再利用できる形式で表示されます。

言い換えればset、シェルに固有の変数を調べます。その一部はたまたま環境内にありますHOME。コントラストのようなコマンドにより、envおよびprintenvコマンドを実行すると、実際の環境変数を見て。参照してくださいこれを


「インタラクティブシェルでは、$ 1、$ 2などを参照することはできません。」これに対する直接の参照はありますか?これらが対話型シェル環境で設定されるという奇妙なケースに遭遇しましたが、これが「非標準」と見なされるかどうかはわかりません。
user5359531

@ user5359531正直なところ、どこから入手したのかよくわかりません。たぶん、2017年に答えを投稿したとき、私はおそらくあなたが何かをすることはできないと言及してい1="foo"ましたが、後でPOSIXの定義によって「単語」(変数や関数などのオブジェクトの名前)が開始できないことがわかりました数字付き(トピックについて投稿し質問を参照)。位置パラメータは明らかにこの規則の例外です。
セルギーKolodyazhnyy

@ user5359531特に正確ではないため、回答の一部を削除しました。インタラクティブシェルでなどを参照できます$1$2実際、setコマンドを使用して、/bin/sh配列がないという制限を回避することがよくあります。私の注意を喚起してくれてありがとう。また、少し洗練と更新が必要なため、今後数日間で回答を編集します。
セルギーKolodyazhnyy

説明をありがとう。私が午前問題があることをconda、あなたが実行したときにsource conda/bin/activate、かどうかについてもチェックし$1$2等が、それは、引数またはないスクリプトとして実行されたかどうかを判断するために、設定されています。これは、何らかの理由で対話型環境に設定されているシステムで停止します。この非標準的な動作が、対話型環境でこれらの変数を設定するシステムの欠陥であるか、またはスクリプトとして実行されたかどうかを判断するために変数を使用するプログラムの欠陥であるかどうかを把握したいと考えています。
user5359531

@ user5359531 パラメーターのconda確認${N}は間違いなく間違った方法なので、開発者またはそのようなスクリプトの元の作成者にバグレポートを提出することをお勧めします。そこに同じトピックに関する質問ですここここでは、多かれ少なかれポータブルな方法があればチェックすることです${0}スクリプト名と同じであるが、bash実際にはその目的のために環境変数を持っている
Sergiy Kolodyazhnyy

4

$1, $2, $3, ..., ${10}, ${11}変数は、位置パラメータと呼ばれ、bashのマニュアルのセクションで説明しています3.4.1

3.4.1位置パラメータ

位置パラメーターは、1桁の0以外の1つ以上の数字で示されるパラメーターです。位置パラメーターは、シェルの起動時にシェルの引数から割り当てられ、組み込みコマンドsetを使用して再割り当てできます。位置パラメータNは、$ {N}、またはNが1桁の場合は$ Nとして参照できます。位置指定パラメーターは、割り当てステートメントを使用して割り当てることはできません。setおよびshiftビルトインは、それらを設定および設定解除するために使用されます(シェル組み込みコマンドを参照)。シェル関数が実行されると、位置パラメーターは一時的に置き換えられます(シェル関数を参照)。

1桁を超える位置パラメータを展開する場合は、中括弧で囲む必要があります。

これらの特別なパラメータは、非常に次のセクションで説明されています$?$03.4.2

3.4.2特別なパラメーター

シェルはいくつかのパラメーターを特別に扱います。これらのパラメーターは参照のみ可能です。それらへの割り当ては許可されていません。

...

($?)直前に実行されたフォアグラウンドパイプラインの終了ステータスに展開します。

0

($ 0)シェルまたはシェルスクリプトの名前に展開します。これはシェルの初期化時に設定されます。コマンドのファイルを使用してBashが呼び出された場合(シェルスクリプトを参照)、$ 0がそのファイルの名前に設定されます。-cオプションを使用してBashを起動した場合(「Bashの呼び出し」を参照)、実行する文字列(存在する場合)の後の最初の引数に$ 0が設定されます。それ以外の場合は、引数ゼロで指定された、Bashの呼び出しに使用されるファイル名に設定されます。


4

$1$2...は位置パラメータであり、環境変数はもちろんのこと、変数ではありません。

Bourneのようなシェルの用語で$somethingは、パラメータ拡張と呼ばれます(、などの${something#pattern}一部のシェル${array[x]}では${param:offset}${x:|y}さらに多くの拡張演算子をカバーしています)。

さまざまな種類のパラメーターがあります。

  • 変数のように$foo$PATH
  • 位置パラメータ($1$2...スクリプトが受け取った引数)
  • 以下のような他の特殊なパラメータ$0$-$#$*$@$$$!$?...

Bourneのようなシェルの変数名は、1文字のアルファベット(ロケールによって認識されるか、シェルに応じてa-zA-Zに制限される)とアンダースコアで始まり、その後に0個以上の英数字またはアンダースコアが続く必要があります。

シェルに応じて、変数は異なるタイプ(スカラー、配列、ハッシュ)を持つか、特定の属性(読み取り専用、エクスポート、小文字...)を指定できます。

これらの変数のいくつかは、シェルによって作成またはシェルにとって特別な意味を持っている(のような$OPTIND$IFS$_...)

export属性を持つシェル変数は、シェルが実行するコマンドに環境変数として自動的にエクスポートされます

環境変数は、シェル変数とは別の概念です。環境変数をコマンドの実行に渡す唯一の方法は、シェル変数のエクスポートではありません。

VAR=foo
export VAR
printenv VAR

VAR環境変数をprintenvコマンドに渡します(コンテンツを印刷するように指示しています)が、次の方法でも実行できます。

env VAR=foo printenv VAR

または:

perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'

例えば。

環境変数には任意の名前を付けることができます(任意の文字を含めることができますが=、空にすることもできます)。Bourneのようなシェル変数名と互換性のない名前を環境変数に与えることは良い考えではありませんが、可能です。

$ env '#+%=whatever' printenv '#+%'
whatever

シェルは、受け取った環境変数を、名前が有効なシェル変数である環境変数のシェル変数のみにマップします(シェルによっては、などの特別なものを無視します$IFS)。

したがって、1環境変数をコマンドに渡すことができますが:

$ env '1=whatever' printenv 1
whatever

それは、その環境変数でシェルを呼び出すと、$1パラメーターの値が設定されることを意味しません。

$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo

3

いいえ、これらはスクリプトのパラメーターです。たとえば、次のようにスクリプトを呼び出す場合:

mynicescript.sh one two three

スクリプト内では、これらのパラメーターは次のように利用できます。

$1 = one
$2 = two
$3 = three

$ 0はスクリプト自体の名前です。

したがって、スクリプトの外にいるときは、これらの変数は使用できません(/ bin / bash-シェル自体を表示する$ 0を除く)。


「ときにしている外部のスクリプトので、これらの変数は利用できません」あなたは何を意味するのです「外のスクリプトを」私は私の端末でこれらの変数の値を見ることができるので、。
user7681202

2
@ user7681202:ターミナルで表示できるものはどれですか? $0現在の端末プロセス(bashの可能性が高い)を指し、$?単に最後のプロセスの終了コードです。
Jesse_b

gnome-terminalwith arguments(gnome-terminal Hello World)を実行しようとしました。私は見ることができました$0が、私は見ることができなかった$1$2
user7681202

@Jesse_bありがとう、回答に$ 0のコンテンツを追加しました。
ヤロスラフクセラ

1
@ user7681202 gnome-terminalはシェルではなく、ターミナルエミュレーターです(xterm、konsoleなど)。シェルは端末内で実行され、bash / sh / zsh / tcshなどが可能です。スクリプトは、適切なヘッダー(#!/ bin / bashなど)とマスクで指定されたシェルによって解釈可能なコンテンツを含む実行可能ファイルです。通常、接尾辞.shを使用します
Jaroslav Kucera
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.