以下のように変数をエクスポートしたスクリプトがあるとします。
#!/bin/bash
foo(){
eval export one=1
}
foo1(){
eval export two=2
}
(foo)
foo1
echo "one=$one"
echo "two=$two"
ただし、次の出力が得られました。
root@centos1:~>/tmp/test.sh
one=
two=2
$one
の値が表示されず、$two
が表示される理由は何でしょうか。
グローバル変数設定された瞬間から設定が解除されるかプロセスが終了する瞬間まで有効です。グローバル(ローカル)変数は無関係な子プロセスに継承されません(子プロセスがフォーク(サブシェル)の場合、すべてのコピーを取得します-エクスポートまたは非エクスポート)。
グローバルにエクスポートされた変数はグローバル変数に似ていますが、無関係な子プロセスでも(プロセス環境の一部として)自動的に継承されます。 (エクスポートを使用すると、CXXFLAGS
などの変数をmake
などのプロセスに渡すことができます。これは間違いなくシェルのサブシェルではなく、そのmake
スポーンもその変数を取得します。)
あなたの例では()
は、すべてのコピーを取得するサブシェルを作成します。 foo
コマンドは、エクスポートされた変数を追加することによってサブシェルを変更します。その後、サブシェルは、エクスポートされた変数を使用せずに終了します(孫はそれを継承しません)。現在、子プロセスから親プロセスに暗黙的に移動する情報はありません。子供たちが自分の環境で何をするかは、両親に影響を与えません。これが、変数one
が設定されていない理由です。
ところで、これらのeval
sはこのコンテキストでは不要なeval
です。
コマンドを( )
で囲むと、コマンドはサブシェルになります。
これは、パイプを使用する場合、または終了する場合に役立ちます。
( date ; cmd1 ; cmd2 ) | grep ...
最初の3つのコマンドを連結し、出力をgrep
(この場合)に与える結果になります。
{}
を検討するだけでなく、bashのmanページを読むこともできます。
(list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT
below). Variable assignments and builtin commands that affect the
Shell's environment do not remain in effect after the command completes.
The return status is the exit status of list.
{ list; }
list is simply executed in the current Shell environment. list must be
terminated with a newline or semicolon. This is known as a group
command. The return status is the exit status of list.
Note that unlike the metacharacters ( and ), { and } are reserved
words and must occur where a reseved Word is permitted to be recognized.
Since they do not cause a Word break, they must be separated
from list by whitespace or another Shell metacharacter.