これは、Linux のプロセスに関する新しいシリーズの最初の記事です。
このシリーズの焦点は、プロセス環境、プロセス制御、プロセス関係などの実際的な側面にあります。
この記事では、C プログラム内で環境変数を取得および設定する方法について説明します。
Linux プロセス シリーズ:パート 1 (この記事)、パート 2、パート 3
プロセスとは?
プロセスは、実行中のプログラムのインスタンスと考えることができます。これを「プログラムのインスタンス」と呼びました。同じプログラムを 10 回実行すると、対応するプロセスが 10 になるからです。
さらに、各プロセスには独自の一意のプロセス ID があり、それによってシステム内で識別されます。自身の ID の他に、親のプロセス ID もプロセスに関連付けられています。
main() 関数
「C」プログラムは、常に main() 関数の呼び出しから始まります。これは、プログラムの実行時に呼び出される最初の関数です。
main() 関数のプロトタイプは次のとおりです:
int main(int argc, char *argv[]);
上記のプロトタイプでは:
- main() 関数の戻り値の型は「int」です。これは、main() 関数が終了すると、プログラムが終了するためです。また、main() からの戻り値の型は、プログラムが正しく実行されたかどうかを示します。厳密には、main() が「0」を返す場合、プログラムは正常に実行されたと言えます。その他の戻り値は失敗を示します。
- main() 関数は 2 つの引数を受け入れます。 1 つはコマンド ライン引数の数で、もう 1 つはすべてのコマンド ライン引数のリストです。
上記の点を説明する小さなコード例を見てみましょう。
#include<stdio.h> int main(int argc, char *argv[]) { int count = argc; printf("\n The number of arguments passed is [%d] \n", count); int c = 0; while(c < count) { printf("\n The argument [%d] is : [%s]\n", c+1, argv[c]); c++; } return 0; }
上記の C コードは、渡されたコマンド ライン引数の数を出力し、各引数の値も出力します。
プログラムが実行されると、次の出力が表示されます:
$ ./main abc 1 3 The number of arguments passed is [4] The argument [1] is : [./main] The argument [2] is : [abc] The argument [3] is : [1] The argument [4] is : [3]
プログラム「main」に 3 つの引数を渡しましたが、ログは 4 つの引数を受け取ったことを通知します。これは、(実行に使用する) プログラムの名前もコマンドライン引数として扱われるためです。
また、上記のプログラムは端末上で実行したため、main() 関数からの戻り値も端末に送信されます。 bash シェルの特別なパラメーター $? を使用できます。以下に示すように、戻り値を確認します (0 は成功を示します)。
$ echo $? 0
- メイン関数に戻ると、カーネルによって C プログラムが実行されると、「exec」関数を使用してプログラムがトリガーされます。
- 次のステップでは、プログラムの main() 関数の直前に典型的なスタートアップ ルーチンが呼び出されます。
- 同様に、プログラムの実行が終了すると、通常の終了ルーチンも呼び出されます。
- 実行可能ファイルを見ると、start ルーチンと ens ルーチンのアドレスが、呼び出される最初のルーチンと最後のルーチンとして指定されていることがわかります。
- スタートアップ ルーチンは、コマンド ライン引数、環境などをカーネルから受け取り、これらを main() 関数に渡します。
- この開始ルーチンと終了ルーチンを含むセットアップ全体は、コンパイル プロセスのリンク段階でリンカーによって行われます。
環境リスト
Linux プロンプトで「env」コマンドを入力すると、name=value ペアのリストが表示されます。これはシェル環境を表します。同様に、プロセスにも環境があります。プロセス環境にアクセスするには 2 つの方法があります:
<オール>envp[] (3 番目の引数) に関して、main() 関数には 2 つの引数しかないことを前に説明したように、main() 関数の 3 番目の引数はどこから来たのかと尋ねるかもしれません。
歴史的には、main() 関数の 3 番目の引数 (環境配列) が存在していました。しかし、ISO C では、main() 関数が 2 つの引数のみで記述されるように指定されています。したがって、メイン関数を指定するときは、この 3 番目の引数を使用しません。ただし、プログラム内でこの envp[] にアクセスすることはできます。
とにかく、環境リストに戻ると、次のコード スニペットは、プロセス内から環境にアクセスする方法を指定します:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> extern char **environ; int main(int argc, char *argv[]) { int count = 0; printf("\n"); while(environ[count] != NULL) { printf("[%s] :: ", environ[count]); count++; } char *val = getenv("USER"); printf("\n\nCurrent value of environment variable USER is [%s]\n",val); if(setenv("USER","Arora",1)) { printf("\n setenv() failed\n"); return 1; } printf("\n Successfully Added a new value to existing environment variable USER\n"); val = getenv("USER"); printf("\nNew value of environment variable USER is [%s]\n",val); while(1) { sleep(2); } return 0; }
上記のコードでは、グローバル変数「environ」を使用してすべての環境変数にアクセスしています。また、2 つの関数を使用しました:
- getenv – 特定の環境変数の値を取得する
- setenv – 環境変数に新しい値を設定する
上記のプログラムの出力は次のようになります:
$ ./environ [ORBIT_SOCKETDIR=/tmp/orbit-himanshu] :: [SSH_AGENT_PID=1627] :: [TERM=xterm] :: [SHELL=/bin/bash] :: [WINDOWID=39846040] :: [GTK_MODULES=canberra-gtk-module] :: [USER=himanshu] :: [SSH_AUTH_SOCK=/tmp/keyring-6kpqGc/ssh] :: .. .. Current value of environment variable USER is [himanshu] Successfully Added a new value to existing environment variable USER New value of environment variable USER is [Arora]
上記の出力は、環境リスト全体を stdout に出力します。上記のコード スニペットでは、getenv と setenv を使用して USER 環境変数を取得し、その値を変更しています。