一、前言
每个程序都接收到一张环境表。它是一个字符指针数组,其中每个指针包含一个以 null 结尾的字符串的地址。全局变量environ则包含了该指针数组的地址:extern char **environ;
二、在shell 中获取环境变量
1. 使用 env 命令可以列出当前shell环境下的所有环境变量
2. 使用echo $环境变量名命令可以查看单个环境变量
3. 使用 PATH=$PATH:/home/ckt/work 可追加环境变量
三、通过函数存取环境变量
要想在代码中使用这个数组,需要前面的声明,否则 environ 是一个非定义的符号,环境由 name=value 这样形式的字符串组成,大多数预定义名完全由大写字母组成,但是不保证全部是这样。内核并不查看这些字符串,它们的解释完全取决于各个应用程序,通常使用 getenv 和 putenv 函数来访问特定的环境变量,而不是用 environ 变量,但是要查看整个环境,就必须要用 environ 指针。
#include <stdlib.h>
char *getenv(const char *name);
函数返回一个指针,它指向 name=value 字符串中的value,若未找到则返回 null,我们应当使用getenv从环境中取一个指定环境变量的值,而不是直接访问 environ。
除了取环境变量的值,有时也需要设置环境变量。我们可能希望改变现有变量的值,或者增加新的环境变量。我们能影响的只是当前进程及调用的任何子进程的环境,但不能影响父进程的环境,这通常是一个shell进程。尽管如此,修改环境变量的能力仍然是很有用的。
#include <stdlib.h>
int putenv( char *str );
int setenv( const char *name, const char *value, int rewrite );
int unsetenv( const char *name );
这三个函数成功返回0,出错返回非0值,接着来看一下它们的区别:
-
putenv取形式为name=value的字符串,将其放到环境表中,如果name已经存在,则先删除其原来的定义。
-
setenv将name设置为value,如果在环境中name已经存在且 rewrite 非0,则首先删除其现有的定义,否则不删除其现有定义,name不设置为新的value,而且也不会出错。
-
unsetenv 删除 name 的定义,即使不存在这种定义也不算出错。
四、存取环境变量原理
1. 如果修改一个现有的name
(a)如果新value的长度少于或等于现有value的长度,则只要在原字符串所用空间中写入新字符串。
(b)如果新value的长度大干原长度,则必须调用malloc为新字符串分配空间,然后将新字符串复制到该空间中,接着使环境表中针对name的指针指向新分配区。
2. 如果要增加一一个新的name,则操作就更加复杂。首先,调用malloc 为name = value字符串分配空间,然后将该字符串复制到此空间中,则:
(a)如果这是第一次增加- ~个新name,则必须调用malloc为新的指针表分配空间。接着,将原来的环境表复制到新分配区,并将指向新name = value字符串的指针存放在该指针表的表尾,然后又将- -个空指针存放在其后。最后使environ指向新指针表。再看一下图7-3,如果原来的环境表位于栈顶之上(这是- -种常见情况),那么必须将此表移至堆中。但是,此表中的大多数指针仍指向栈顶之上的各name=value字符串。
(b)如果这不是第-一次增加一个新name ,则可知以前已调用ma1loc在堆中为环境表分配了空间,所以只要调用realloc,以分配比原空间多存放一个指针的空间。然后将指向新name = value字符串的指针存放在该表表尾,后面跟着-一个空指针。