2012-04-03 19 views
8

ここではsystem呼び出しを使用してhi.shファイルを実行するCプログラムを作成しました。ここでCコードを使用して環境変数を取得

私はので、私は同じシェル にこのスクリプトを実行してからのgetenv関数を使用して環境変数を取得するために試してみたいが、ここで私は私が期待したものとは異なる出力を取得しています. ./hi.shを使用。

hi.shファイルは、私は同じシェルで10にシステムコール、そのexport TESTセット値を使用して、このhi.shファイルを実行すると

export TEST=10 
return 

の意味が含まれています。 この後、私はこの変数の値を取得しようとしていますが、与えられたNULLの値です。

そして、私は. ./hi.shのように、コンソールから手動でこのスクリプトを実行する場合、それは正常に動作し、私はgetenv("TEST")機能を使用してTESTの10値を取得します。

コード:

#include <stdio.h> 
int main() 
{ 
    system(". ./hi.sh"); 
    char *errcode; 
    char *env = "TEST"; 
    int errCode;  
    errcode = getenv(env); 
    printf("Value is = %s\n",errcode); 
    if (errcode != NULL) { 
     errCode =atoi(errcode); 
     printf("Value is = %d\n",errCode); 
    } 
} 

出力:

Value is = (null) 

私はプログラムシェルでTEST変数をエクスポートすることができますどのように? system()が別のシェルでコマンドを実行する場合、Cプログラムコードを使用して、system()呼び出しによって呼び出されるシェルによってエクスポートされる環境変数を取得する方法はありますか?

答えて

7

いつものように、マニュアルページで説明していますが、非常に注意深く読む必要があります。言い換えれば

DESCRIPTION 
     system() executes a command specified in command by calling /bin/sh -c 
     command, and returns after the command has been completed. During exe‐ 
     cution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT 
     will be ignored. 

、システム()最初の開始/ binに/ SH、および/ binに/あなたが実行したいものは何でもコマンド起動SHました。 ここで何が起きるかは、TEST変数が/ bin/shシェルにエクスポートされ、system()呼び出しが暗黙的に開始されたが、system()が呼び出されたプログラムにはエクスポートされないということです。

+0

この目標を達成するにはどうすればよいですか? – user1089679

+0

TEST変数をプログラムシェルにどのようにエクスポートできますか? – user1089679

+2

@ user1089679 Cプログラムを実行する前に、スクリプトを用意してください(環境を設定してください)。環境変数はどのように使用するように設計されています。 –

0

その後、黙って子プロセスに渡し、または明示的にシェルスクリプトを実行するためにfork()execve()を使用して変数を渡すsystem()setenv()を(使用して、独自のプロセスで環境変数を設定することができます。

+0

あなたの返信に感謝します。しかし、私はシステムコールとそのスクリプトから環境変数を設定するために必要なシェルスクリプトを呼び出す必要があります。その後、私はシェルから環境変数を取得したい – user1089679

+2

これは不可能です。変数は新しく作成されたプロセスにのみ渡すことができ、親プロセスに戻すことはできません。あなたのスクリプトは、 'system()'の代わりに 'popen()'を使って取り出すことができるいくつかの出力を生成する必要があります。 –

9

子プロセスは直接親プロセスの環境を設定することはできません。アプローチので、失敗する運命にあるsystem()getenv()を使用。

スクリプトhi.shによって設定され、選択された変数をインポートしようとしている場合、あなたは選択肢のカップルを持っている。いずれにします読めるスクリプトhi.shを設定し、それを設定する(やや難しい)か、スクリプトを実行して、実行するコードを対象の環境変数に戻すことができます。

hi.sh$ENV1$ENV2と設定されているとします。 popen()を使用して値をプログラムに戻し、setenv()を使用してプログラムの環境を設定することができます。概要:

FILE *fp = popen(". ./hi.sh; echo ENV1=$ENV1; echo ENV2=$ENV2", "r"); 

while (fgets(buffer, sizeof(buffer), fp) != 0) 
{ 
    ...split the buffer into env_name, env_value... 
    setenv(env_name, env_value); 
} 

pclose(fp); 

私はエコー情報に変数名を含めました。これは人生を簡素化します。変数リストが扱いにくい場合は、". ./hi.sh; env"を実行して環境全体を取得し、各行を読み込み、変数設定を使用するかどうかをビルトインリストから確認してください。そうであれば、環境全体を再度設定することもできます。 setenv()関数が成功したことを確認する必要があります(成功した場合は0を返します)。また、popen()が成功したことを確認する必要があります(fp != 0)。この文脈では、おそらくstrtok()を使用して、=が値から変数名を分離するのを探すことができます。それは名前を終了し、null値を終了し、あなたにはnullを与え、=以上のNULLバイトを踏みにじる:

char *env_name = strtok(buffer, "="); 
    char *env_value = buffer + strlen(env_name) + 1; 
    if (setenv(env_name, env_value) != 0) 
     ...report trouble... 
1

別の可能な解決策は、別のシェルを介してプログラムexec自体を持つことです。そのシェルは実行中のプログラムを置き換えてから、環境変数を読み込み、シェルをプログラムの新しいコピーに置き換えます。新しいコピーに、既にexecを行ったことを伝える必要があります。それは何度も何度も何度もやり直すことになります。環境変数を探すか、コマンドラインフラグを渡すことができます。

テストされていない例:あなたは本当のプログラム名が何であれでa.outを交換する必要があるだろう

execl("/bin/sh", "-c", ". ./hi.sh; exec ./a.out --envset", NULL); 

。 argv [0]からそれを抽出し、残りのargv配列も渡したいと思うでしょう。しかし、シェル引数として動作するように引数を再フォーマットする必要があるため、必要に応じて引用符を付ける必要があります。

関連する問題