回答:
環境は、見た目ほど魔法ではありません。シェルはそれをメモリに保存し、execve()
システムコールに渡します。子プロセスは、それをという配列ポインタとして継承しますenviron
。execve
マンページから:
あらすじ
#include <unistd.h> int execve(const char *filename, char *const argv[], char *const envp[]);
argv
新しいプログラムに渡される引数文字列の配列です。
慣例により、これらの文字列の最初には、実行中のファイルに関連付けられたファイル名が含まれている必要があります。envp
環境として新しいプログラムに渡される、通常はkey = valueの形式の文字列の配列です。
environ(7)
マニュアルページにも、いくつかの洞察力を提供しています:
あらすじ
extern char **environ;
説明
変数
environ
は、「環境」と呼ばれる文字列へのポインタの配列を指します。この配列の最後のポインターには値がありますNULL
。(この変数はユーザープログラムで宣言する必要があり<unistd.h>
ますが、ヘッダーファイルがlibc4またはlibc5から来た場合、およびそれらがglibcから来て_GNU_SOURCEが定義されている場合、ヘッダーファイルで宣言されます。)プロセスを開始したexec(3)呼び出しによるプロセス。
exec*e
暗黙的にenviron
グローバル変数を使用する代わりに、envを明示的に渡すバリアントです。v
手段「ベクター」、およびアレイ(よりむしろ「リスト」(可変長関数))として渡されたコマンドライン引数を指す execve
システムコールであり、そして他のすべてのexec*
機能は、それのためのlibcラッパーです。
少し間違っています:SOME_NAME=value
シェル変数を作成します(ほとんどのシェルで)。export SOME_NAME=value
環境変数を作成します。良くも悪くも、ほとんどのUnix / Linux / * BSDシェルは、環境変数とシェル変数にアクセスする際に同一の構文を使用します。
もっと大きな意味では、「環境」はプログラムの実行に伴う情報にすぎません。Cプログラムでは、getpid()
呼び出しでプロセスIDを見つけることができます。シェルプログラムでは、変数アクセスを使用します$$
。プロセスIDは、プログラムの環境の一部にすぎません。「環境」という用語は、プログラム実行のモデリングなど、より理論的なコンピューターサイエンスのトピックに由来すると考えています。プログラム実行のモデルには、「変数とその値の間の関連を含む」環境があります。
そして後者のより強力な定義は、Unix / Linux / * BSDシェルの「環境」とは何か:名前(「変数」)とその値との関連付けです。ほとんどのUnixスタイルのシェルでは、値はすべて文字列ですが、以前ほど厳密ではありません。最近では、Ksh、Zsh、およびBashにはすべて型変数があります。シェル関数定義もエクスポートできます。
プレーンシェル変数とは別の環境を使用するには、fork/exec
すべてのUnixが使用する新しいプロセスを開始する方法が必要です。いつexport
名前/値のペア、その名前/値のペアを持つシェルによって開始された新しい実行ファイルの環境中に存在するであろうexecve(2)
(通常は、以下のシステムコールfork(2)
場合を除いて、exec
シェルコマンドを使用しました)。
に続いてexecve()
、main()
新しいバイナリの関数には、コマンドライン引数、環境(var=value
文字列へのポインターのNULL終了配列として格納されます。man environ(7)
ページを参照)があります。継承されるその他の状態には、ulimit
設定、現在の作業ディレクトリ、およびexecve()
呼び出し側がFD_CLOEXECを設定していないオープンファイル記述子が含まれます。ttyの現在の状態(エコー有効、rawモードなど)は、新しく作成されたexec
プロセスに継承された実行状態の一部と見なすこともできます。
簡単なコマンド(組み込み関数またはシェル関数以外)bash
については、実行環境に関するマニュアルの説明を参照してください。
Unix環境は、少なくとも他のいくつかのオペレーティングシステムとは異なります。VMSの「字句」は、子プロセスによって変更でき、その変更は親で確認できます。cd
子プロセスのVMS は、親の作業ディレクトリに影響します。少なくともいくつかの状況では、私の記憶は私を失敗させているかもしれません。
いくつかの環境変数は、よく知られており$HOME
、$PATH
、$LD_LIBRARY_PATH
など。一部は特定のプログラミングシステムに慣習的であるため、親シェルは、特定の一時ディレクトリ、またはに表示されないユーザーIDとパスワードなど、多くの特別な目的の情報をプログラムに渡すことができますps -ef
。単純なCGIプログラムは、たとえば環境変数を介してWebサーバーから多くの情報を継承します。
SOME_NAME=value command
そのコマンド呼び出しのSOME_NAME環境変数を設定します。紛らわしいことに、同じ名前のシェル変数を設定していないようです。
SOME_NAME=value command
期待に反して振る舞う理由は、「コマンドに渡される環境にSOME_NAMEを追加するが、このシェルの変数を変更しない」ことを意味する特別な構文であるためです。
fork()
編が、彼らはやるシェル変数(のコピー)を受け取ります。
最も生の形式の環境変数は、名前/値のペアのセットです。man 1 bash
環境セクションのbashのマニュアルページ()で説明されているように:
When a program is invoked it is given an array of strings called the
environment. This is a list of name-value pairs, of the form
name=value.
The shell provides several ways to manipulate the environment. On
invocation, the shell scans its own environment and creates a parameter
for each name found, automatically marking it for export to child pro-
cesses. Executed commands inherit the environment.
実際的には、現在のシェルから呼び出されたプログラムに共有または固有の動作を定義できます。たとえば、使用する場合、crontab
または環境変数を定義して、システムがデフォルトで使用するエディター以外の別のエディターを定義するvisudo
ことができEDITOR
ます。同じことがman
、PAGER
環境を調べてマニュアルページの出力を表示するために使用するページャープログラムを決定するコマンドなどの場合にも当てはまります。
多くのUNIXコマンドが環境を読み取り、そこに設定されている内容に応じて、これらに応じて出力/処理/アクションを変更します。一部は共有され、一部はプログラムに固有です。ほとんどのマニュアルページには、環境変数が説明されているプログラムにどのように影響するかに関する情報が含まれています。
他の実用的な図は、同じプラットフォーム上に複数のOracleがインストールされているシステムなどのものです。を設定することによりORACLE_HOME
、(PATH
環境変数からロードされた)oracleコマンドのスイート全体が、その最上位ディレクトリの下から設定、定義、マッピング、およびライブラリを取得します。JAVA_HOME
環境変数を使用したjavaなどの他のプログラムにも同じことが当てはまります。
bashの自体は、多くの歴史から物事の範囲の動作を変更することができ、環境変数(持っているHISTSIZE
、HISTFILE
など)、画面サイズ(COLUMNS
)、タブ補完(FIGNORE
、GLOBIGNORE
)ロケールと文字エンコーディング/デコーディングを(LANG
、LC_*
)(、プロンプトPS1
... PS4
)、およびなど(再度bashのマニュアルページから知識を求めます)。
また、独自のカスタム環境変数を使用するスクリプト/プログラムを作成することもできます(設定を渡す、または機能を変更するため)。
「環境変数」は、実行中のプロセスがコンピューター上で動作する方法に影響を与える可能性がある動的な名前付きの値のセットです。
これらは、プロセスが実行されるオペレーティング環境の一部です。たとえば、実行中のプロセスは、TEMP環境変数の値を照会して一時ファイルを保存する適切な場所を見つけたり、HOMEまたはUSERPROFILE変数を呼び出してプロセスを実行しているユーザーが所有するディレクトリ構造を見つけたりできます。
詳細はこちら→ http://en.wikipedia.org/wiki/Environment_variable。
環境変数について知りたいことすべて...↑
この回答には、変数、値、変数置換、プロンプト、エコー、カーネル、シェル、ユーティリティ、セッション、プロセスという用語に関するシェルスクリプトの経験と知識が必要です。
環境変数(ENVAR)指定されたプロセスは、コンピュータのオペレーティングシステム上で動作します方法を行うことができるグローバル定義された変数の集合です。
envarsをa $
および大文字で置き換えます。例:$PS1
。
この方法でenvarを印刷できます。
echo $PS1
$PS1
Unixプロンプトの値を保持します。そのネイティブの値はであるとし\u
\w
$
ます。
\u
(現在の)ユーザーを表し、\w
作業ディレクトリを表し、$
プロンプトの境界を定めることです。だから、私たちがしなければ:echo $PS1
、我々はの値を参照してください\u
、\w
プラス最後にドル記号。
そのenvarの値を変更すると、そのコンテキストでUnixの動作を変更できます。例えば:
PS1="\w >"
プロンプトは次のようになります(作業ディレクトリの名前が「John」であると仮定):
John >
できることと同じ方法PS1="Hello, I'm your prompt >"
で、以下echo $PS1
をもたらします。
Hello, I'm your prompt >
Bash 4.xxでは、env
コマンドを使用してシステム内のすべてのenvarを出力できます。env
ターミナルで実行することをお勧めし、出力を確認します。
セッションのターミナルでは、Bashに付属するenvarをカスタマイズできます。
前述の変更は通常一時的なものであり、その理由は次のとおりです。
各セッション(サブセッションではない)は一意であり、複数のプロセスを同時に一意に実行できます(それぞれ独自の一連のenvarsを使用)が、通常はセッション0からセッション1以上に継承があります。
1つのプロセスに加えた変更はそのプロセスに固有のものであり、何らかの方法で保存せずに閉じた場合に停止します。
選択したスコープに応じて、envarの変更を保存する方法はいくつかあります。このような変更のさまざまなスコープ(レベル)は次のとおりです。
Unixは、カーネル、シェル、ユーティリティの3つの主要な層で構成されています。私の知る限り、各シェルには独自のエンバーがあり、これらは主にまたは排他的にシェル内に構築されます。
これらをグローバルに変更する特定の場所は通常/etc/profile
ですが.bashrc
、もちろんそれもできます。
新しいenvarを作成できます。ここに方法があります。Bash 4.xxの時点では、ネイティブenavarという名前はありませんMESSAGE
(前述のとおり、envarは通常大文字です)。
MESSAGE="Hello world!"
これを作成して、echo $MESSAGE
と入力するとが得られhello world!
ます。
bash
現在の作業セッション(ウィンドウ)で実行する場合、新しいbashサブセッションを開始し、実行しない限り、元のプロセスでは動作しなくなりexit
ます。
注:ターミナルエミュレーターを備えたオペレーティングシステム(Ubuntuデスクトップなど)では、サブセッションは通常同じウィンドウで実行されますが、別のウィンドウの新しいセッションは既存のサブセッションではありません(隣接するプロセスです) 。
注:envar値に!などの特別な記号を使用しないでください。または保存されません。
最初のセッションで作成されたenvarは、ユーザーレベルまたはグローバルレベルのconfファイルに登録せずに、2番目のセッションでも使用できます(次のデータを参照)。その方法は次のとおりです。
元のセッション(現在のウィンドウまたは別のウィンドウ)に移動して、次を実行します。
export MESSAGE
エクスポートするときは、$
記号を使用しないでください。
現在、すべてのサブセッションにエクスポートされています。echo $MESSAGE
サブセッションで行う場合は、ユーザーからでも別からでも、印刷されます。
などのシェル内部変数PS1
はエクスポートしないでくださいが、何らかの理由でそれらをエクスポートしたいが表示されない場合は、bash
後export
に実行せず、むしろを実行してくださいbash –norc
。
$PATH
ユーザーが通常最も変更する環境変数です。
の場合echo $PATH
、このストリームが表示されます。
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
このenvarの出力値はコロン(:)で区切られていますが、より快適な方法があります(これらは同じ値です)。
/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games
これらは、ユーティリティを実行するときに検索するディレクトリです。
実行which echo
することで、ファイルの場所を取得します/bin/echo
。たとえば、に存在することがわかります。
それに基づいて、echo envarと入力してevnarの値を表示する必要はありません。次のこともできます。
/bin/echo $ENVAR
envarは引き続き実行されます。例:
/bin/echo $HOME
私たちに与えます
/home/User || /root
同じように:
echo $HOME
私たちに与えます
/home/User || /root
注:$HOME
はと略され~
ます。
Bash 4.xxでは、フルパスなしでユーティリティを使用すると、システムは上記の6つの値すべてを使用します$PATH
。したがって、それはから始まり、/user/local/bin
すべてのコンテンツに従ってecho
実行可能ファイルを探します。
この場合、で停止し/bin/echo
ます。この場合、実行可能ファイルが存在します。
したがって、$PATH
envarをカスタマイズする主な理由は、ネイティブ値のいずれにも属さない実行可能ファイルをインストールすることです。
そのような実行可能ファイルをインストールした後$PATH
、それに応じて値を設定する必要があります。そうすれば、それらのファイルを操作できるようになります。
$PATH
:次の方法でexport $PATH
、サブセッション(WordPressのWP-CLIやDrupalのDrushなどのbash拡張機能を含む)をbash できます。
export PATH="/home/John:$PATH"
これにより、に新しい値が追加さ/home/John
れ$PATH
、その後すぐに、ネイティブ値(コロンの直後)が付加されます$PATH
。これらは構文の下に格納されます。
このような永続的な変更は、関連するスクリプトで、通常/etc/profile
、名前の下に名前で行うことができます.bashrc
。
!
は非常に多くの間違いがあります:セッションとプロセスの融合、動作を示す例のすぐ下にある環境変数値の動作に関する警告、サブセッションの誤った概念、何をすべきかについての非常に奇妙なアドバイスシェル変数とグローバル環境変数の誤った概念をエクスポートした後。
warning about ! in an environment variable value not working that is right below an example showing it working
?例としてください。
quite bizarre advice about what to do after exporting a shell variable
、正確にはどういう意味ですか?
false notion of global environment variables
、正確にはどういう意味ですか?
exec(3)
ファミリーの一部のメンバー(つまり、exec * vに一致しないメンバー)が** environを隠れて通過することは、おそらく注目に値します。