web-dev-qa-db-ja.com

シェルでエクスポートされた変数のスコープ

以下のように変数をエクスポートしたスクリプトがあるとします。

#!/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が表示される理由は何でしょうか。

4

グローバル変数設定された瞬間から設定が解除されるかプロセスが終了する瞬間まで有効です。グローバル(ローカル)変数は無関係な子プロセスに継承されません(子プロセスがフォーク(サブシェル)の場合、すべてのコピーを取得します-エクスポートまたは非エクスポート)。

グローバルにエクスポートされた変数はグローバル変数に似ていますが、無関係な子プロセスでも(プロセス環境の一部として)自動的に継承されます。 (エクスポートを使用すると、CXXFLAGSなどの変数をmakeなどのプロセスに渡すことができます。これは間違いなくシェルのサブシェルではなく、そのmakeスポーンもその変数を取得します。)

あなたの例では()は、すべてのコピーを取得するサブシェルを作成します。 fooコマンドは、エクスポートされた変数を追加することによってサブシェルを変更します。その後、サブシェルは、エクスポートされた変数を使用せずに終了します(孫はそれを継承しません)。現在、子プロセスから親プロセスに暗黙的に移動する情報はありません。子供たちが自分の環境で何をするかは、両親に影響を与えません。これが、変数oneが設定されていない理由です。


ところで、これらのevalsはこのコンテキストでは不要なevalです。

7
PSkocik

コマンドを( )で囲むと、コマンドはサブシェルになります。

これは、パイプを使用する場合、または終了する場合に役立ちます。

( 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.
1
Archemar