初识环境变量
问题:环境变量是什么?有什么意义?
int create_process(char *path, char *args[])
{
int ret = fork();
if (ret == 0) {
execve(path, args, NULL);
}
return ret;
}
main 函数(默认进程入口)
int main(int argc, char *argv[], char *env[])
- argc 命令行参数个数 (启动参数)
- argv[] - 命令行参数数组 (启动参数)
- env[] - 环境变量数组(最后一个元素为 NULL)
什么是环境变量
- 环境变量是进程运行过程中可能用到的
"键值对"
(NAME = Value) - 进程拥有一个环境表(environment list),环境表包含了环境变量
- 环境表用于
记录系统中相对固定的共享信息
(不特定于具体进程) - 进程之间的环境表互相独立(环境表可在父子进程之间传递)
环境表的构成
下面的程序输出什么?为什么?
parent.c
#include
#include
#include
#define EXE "child.out"
int create_process(char *path, char *args[], char *env[])
{
int ret = fork();
if (ret == 0) {
execve(path, args, env);
}
return ret;
}
int main()
{
char path[] = EXE;
char arg1[] = "hello";
char arg2[] = "world";
char *args[] = {path, arg1, arg2, NULL};
printf("%d begin\n", getpid());
printf("%d child = %d\n", getpid(), create_process(EXE, args, args));
printf("%d end\n", getpid());
return 0;
}
child.c
#include
#include
#include
int main(int argc, char *argv[], char *env[])
{
int i = 0;
sleep(1);
printf("process parameter:\n");
for (i=0; i
tiansong@tiansong:~/Desktop/linux$ ./parent.out
3581 begin
3581 child = 3582
3581 end
tiansong@tiansong:~/Desktop/linux$ process parameter:
exec = 3582 child.out
exec = 3582 hello
exec = 3582 world
enviroment list:
exec = 3582 child.out
exec = 3582 hello
exec = 3582 world
tiansong@tiansong:~/Desktop/linux$ ./child.out a b c
process parameter:
exec = 3641 ./child.out
exec = 3641 a
exec = 3641 b
exec = 3641 c
enviroment list:
exec = 3641 SHELL=/bin/bash
exec = 3641 COLORTERM=truecolor
exec = 3641 TERM_PROGRAM_VERSION=1.82.1
exec = 3641 LC_ADDRESS=zh_CN.UTF-8
exec = 3641 LC_NAME=zh_CN.UTF-8
exec = 3641 LC_MONETARY=zh_CN.UTF-8
exec = 3641 PWD=/home/tiansong/Desktop/linux
exec = 3641 LOGNAME=tiansong
exec = 3641 XDG_SESSION_TYPE=tty
exec = 3641 VSCODE_GIT_ASKPASS_NODE=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/node
exec = 3641 MOTD_SHOWN=pam
exec = 3641 HOME=/home/tiansong
exec = 3641 LANG=en_US.UTF-8
exec = 3641 LC_PAPER=zh_CN.UTF-8
exec = 3641 LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
exec = 3641 GIT_ASKPASS=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/extensions/git/dist/askpass.sh
exec = 3641 SSH_CONNECTION=192.168.112.1 6125 192.168.112.128 22
exec = 3641 VSCODE_GIT_ASKPASS_EXTRA_ARGS=
exec = 3641 LESSCLOSE=/usr/bin/lesspipe %s %s
exec = 3641 XDG_SESSION_CLASS=user
exec = 3641 TERM=xterm-256color
exec = 3641 LC_IDENTIFICATION=zh_CN.UTF-8
exec = 3641 LESSOPEN=| /usr/bin/lesspipe %s
exec = 3641 USER=tiansong
exec = 3641 VSCODE_GIT_IPC_HANDLE=/run/user/1000/vscode-git-9f60bfa27b.sock
exec = 3641 SHLVL=2
exec = 3641 LC_TELEPHONE=zh_CN.UTF-8
exec = 3641 LC_MEASUREMENT=zh_CN.UTF-8
exec = 3641 XDG_SESSION_ID=7
exec = 3641 XDG_RUNTIME_DIR=/run/user/1000
exec = 3641 SSH_CLIENT=192.168.112.1 6125 22
exec = 3641 LC_TIME=zh_CN.UTF-8
exec = 3641 VSCODE_GIT_ASKPASS_MAIN=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/extensions/git/dist/askpass-main.js
exec = 3641 XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
exec = 3641 BROWSER=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/bin/helpers/browser.sh
exec = 3641 PATH=/home/tiansong/openharmony/toolchain/gcc-arm-none-eabi-10.3-2021.10/bin:/home/tiansong/openharmony/toolchain/xtensa-esp32-elf:/home/tiansong/openharmony/toolchain/xtensa-esp32s3-elf/bin:/home/tiansong/openharmony/toolchain/gcc_riscv32/bin:/home/tiansong/.local/bin:/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/bin/remote-cli:/home/tiansong/.local/bin:/home/tiansong/openharmony/toolchain/gcc-arm-none-eabi-10.3-2021.10/bin:/home/tiansong/openharmony/toolchain/xtensa-esp32-elf:/home/tiansong/openharmony/toolchain/xtensa-esp32s3-elf/bin:/home/tiansong/openharmony/toolchain/gcc_riscv32/bin:/home/tiansong/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
exec = 3641 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
exec = 3641 LC_NUMERIC=zh_CN.UTF-8
exec = 3641 OLDPWD=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585
exec = 3641 TERM_PROGRAM=vscode
exec = 3641 VSCODE_IPC_HOOK_CLI=/run/user/1000/vscode-ipc-68bc0605-d193-46cd-bf03-3029b6c8175b.sock
exec = 3641 _=./child.out
tiansong@tiansong:~/Desktop/linux$ echo $USER
tiansong
tiansong@tiansong:~/Desktop/linux$ echo $SHLVL
2
tiansong@tiansong:~/Desktop/linux$ echo $PATH
/home/tiansong/openharmony/toolchain/gcc-arm-none-eabi-10.3-2021.10/bin:/home/tiansong/openharmony/toolchain/xtensa-esp32-elf:/home/tiansong/openharmony/toolchain/xtensa-esp32s3-elf/bin:/home/tiansong/openharmony/toolchain/gcc_riscv32/bin:/home/tiansong/.local/bin:/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/bin/remote-cli:/home/tiansong/.local/bin:/home/tiansong/openharmony/toolchain/gcc-arm-none-eabi-10.3-2021.10/bin:/home/tiansong/openharmony/toolchain/xtensa-esp32-elf:/home/tiansong/openharmony/toolchain/xtensa-esp32s3-elf/bin:/home/tiansong/openharmony/toolchain/gcc_riscv32/bin:/home/tiansong/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
实验表明,环境变量是存储在环境表中的,环境表在代码中是一个字符串数组,字符串数组记录了系统中的关键信息,而这些关键信息可以看坐是特殊的进程参数.
理解环境变量
深入理解环境变量
- 对于进程来说,环境变量是一种特殊的参数
- 环境变量相对于启动参数较稳定(系统定义 且 各个进程共享)
- 环境变量遵守固定规范 (如:键值对,变量名大写)
- 环境变量 与 启动参数 存储于进程中同一内存区域(私有)
环境变量读写接口
- 头文件:
#include
读:
char *getenv(const char *name);
- 返回 name 环境变量的值,如果不存在,返回 NULL
写:
int putenv(char *string);
- 设置 / 改变环境变量 (NAME = Value), string 不能是栈上定义的字符串
- 如果环境变量存在,改变值; 如果环境变量不存在,则创建
putenv("TEST");
→ 环境变量被清空 (TEST = NULL)
- 环境表入口:
extern char **environ;
下面的程序输出什么?为什么?
#include
#include
#include
extern char **environ;
int main()
{
int i = 0;
printf("original:\n");
printf("%s=%s\n", "TEST1", getenv("TEST1"));
printf("%s=%s\n", "TEST2", getenv("TEST2"));
printf("%s=%s\n", "TEST3", getenv("TEST3"));
putenv("TEST1");
putenv("TEST2=NEW-VALUE");
putenv("TEST3=CREATE NEW");
printf("changed:\n");
printf("%s=%s\n", "TEST1", getenv("TEST1"));
printf("%s=%s\n", "TEST2", getenv("TEST2"));
printf("%s=%s\n", "TEST3", getenv("TEST3"));
while (environ[i]) {
printf("exec = %d %s\n", getpid(), environ[i++]);
}
return 0;
}
tiansong@tiansong:~/Desktop/linux$ gcc env.c -o env.out
tiansong@tiansong:~/Desktop/linux$ ./env.out
original:
TEST1=(null)
TEST2=(null)
TEST3=(null)
changed:
TEST1=(null)
TEST2=NEW-VALUE
TEST3=CREATE NEW
exec = 4403 SHELL=/bin/bash
exec = 4403 COLORTERM=truecolor
exec = 4403 TERM_PROGRAM_VERSION=1.82.1
exec = 4403 LC_ADDRESS=zh_CN.UTF-8
exec = 4403 LC_NAME=zh_CN.UTF-8
exec = 4403 LC_MONETARY=zh_CN.UTF-8
exec = 4403 PWD=/home/tiansong/Desktop/linux
exec = 4403 LOGNAME=tiansong
exec = 4403 XDG_SESSION_TYPE=tty
exec = 4403 VSCODE_GIT_ASKPASS_NODE=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/node
exec = 4403 MOTD_SHOWN=pam
exec = 4403 HOME=/home/tiansong
exec = 4403 LANG=en_US.UTF-8
exec = 4403 LC_PAPER=zh_CN.UTF-8
exec = 4403 LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
exec = 4403 GIT_ASKPASS=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/extensions/git/dist/askpass.sh
exec = 4403 SSH_CONNECTION=192.168.112.1 6125 192.168.112.128 22
exec = 4403 VSCODE_GIT_ASKPASS_EXTRA_ARGS=
exec = 4403 LESSCLOSE=/usr/bin/lesspipe %s %s
exec = 4403 XDG_SESSION_CLASS=user
exec = 4403 TERM=xterm-256color
exec = 4403 LC_IDENTIFICATION=zh_CN.UTF-8
exec = 4403 LESSOPEN=| /usr/bin/lesspipe %s
exec = 4403 USER=tiansong
exec = 4403 VSCODE_GIT_IPC_HANDLE=/run/user/1000/vscode-git-9f60bfa27b.sock
exec = 4403 SHLVL=2
exec = 4403 LC_TELEPHONE=zh_CN.UTF-8
exec = 4403 LC_MEASUREMENT=zh_CN.UTF-8
exec = 4403 XDG_SESSION_ID=7
exec = 4403 XDG_RUNTIME_DIR=/run/user/1000
exec = 4403 SSH_CLIENT=192.168.112.1 6125 22
exec = 4403 LC_TIME=zh_CN.UTF-8
exec = 4403 VSCODE_GIT_ASKPASS_MAIN=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/extensions/git/dist/askpass-main.js
exec = 4403 XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
exec = 4403 BROWSER=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/bin/helpers/browser.sh
exec = 4403 PATH=/home/tiansong/openharmony/toolchain/gcc-arm-none-eabi-10.3-2021.10/bin:/home/tiansong/openharmony/toolchain/xtensa-esp32-elf:/home/tiansong/openharmony/toolchain/xtensa-esp32s3-elf/bin:/home/tiansong/openharmony/toolchain/gcc_riscv32/bin:/home/tiansong/.local/bin:/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585/bin/remote-cli:/home/tiansong/.local/bin:/home/tiansong/openharmony/toolchain/gcc-arm-none-eabi-10.3-2021.10/bin:/home/tiansong/openharmony/toolchain/xtensa-esp32-elf:/home/tiansong/openharmony/toolchain/xtensa-esp32s3-elf/bin:/home/tiansong/openharmony/toolchain/gcc_riscv32/bin:/home/tiansong/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
exec = 4403 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
exec = 4403 LC_NUMERIC=zh_CN.UTF-8
exec = 4403 OLDPWD=/home/tiansong/.vscode-server/bin/6509174151d557a81c9d0b5f8a5a1e9274db5585
exec = 4403 TERM_PROGRAM=vscode
exec = 4403 VSCODE_IPC_HOOK_CLI=/run/user/1000/vscode-ipc-68bc0605-d193-46cd-bf03-3029b6c8175b.sock
exec = 4403 _=./env.out
exec = 4403 TEST2=NEW-VALUE
exec = 4403 TEST3=CREATE NEW
综合编程小练习
- 编写应用程序,通过命令行参数读写环境变量
选项定义:
- -a : 无选项值,输出所有环境变量
- -r : 读环境变量, -n → 环境变量名
- -w : 写环境变量, -n → 环境变量名, -v → 环境变量值
- -t : 环境变量读写测试,先写入指定环境变量,之后输出所有环境变量
main.c
#include
#include
#include
#include
#include
typedef int OptCall(const char *, const char *);
typedef struct {
const char opt;
OptCall *handler;
}CallHandler;
static int A_Handler(const char *n, const char *v)
{
extern char **environ;
int i = 0;
while (environ[i]) {
printf("%s\n", environ[i++]);
}
return 0;
}
static int R_Handler(const char *n, const char *v)
{
if (n) {
printf("%s=%s\n", n, getenv(n));
} else {
printf("Need environ Name to read value...\n");
}
return 0;
}
static int W_Handler(const char *n, const char *v)
{
int err = 1;
if (n && v) {
char *kv = malloc(strlen(n) + strlen(v) + 2);
if (kv) {
strcpy(kv, n);
strcat(kv, "=");
strcat(kv, v);
err = putenv(kv);
if (!err) {
printf("New Environ: %s\n", kv);
} else {
printf("Error on writing new environ value ...\n");
}
}
// free(kv); // 注意!!此处不能释放
} else {
printf("Need Name and value to write value...\n");
}
return err;
}
static int T_Handler(const char *n, const char *v)
{
return W_Handler(n, v) || A_Handler(n, v);
}
static const CallHandler g_handler[] = {
{'a', A_Handler},
{'r', R_Handler},
{'w', W_Handler},
{'t', T_Handler},
};
static const int g_len = sizeof(g_handler) / sizeof(*g_handler);
int main(int argc, char *argv[])
{
int c = 0;
char opt = 0;
char *name = NULL;
char *value = NULL;
while ((c = getopt(argc, argv, "arwtn:v:")) != -1) {
switch (c)
{
case 'a':
case 'r':
case 'w':
case 't':
opt = c;
break;
case 'n':
name = optarg;
break;
case 'v':
value = optarg;
break;
default:
exit(-1);
}
}
for (c=0; c
tiansong@tiansong:~/Desktop/linux$ gcc main.c -o main.out
tiansong@tiansong:~/Desktop/linux$ ./main.out -w -n TEST -v 123
New Environ: TEST=123
tiansong@tiansong:~/Desktop/linux$ ./main.out -r -n PWD
PWD=/home/tiansong/Desktop/linux
问题:进行参数 和 环境变量 对进程意味着什么?