初識環境變數
問題:環境變數是什麼?有什麼意義?
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 <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#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 <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[], char *env[])
{
int i = 0;
sleep(1);
printf("process parameter:\n");
for (i=0; i<argc; ++i) {
printf("exec = %d %s\n", getpid(), argv[i]);
}
printf("enviroment list:\n");
i = 0;
while (env[i]) {
printf("exec = %d %s\n", getpid(), env[i++]);
}
return 0;
}
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 <stdlib.h>
讀:
char *getenv(const char *name);
- 返回 name 環境變數的值,如果不存在,返回 NULL
寫:
int putenv(char *string);
- 設定 / 改變環境變數 (NAME = Value), string 不能是棧上定義的字串
- 如果環境變數存在,改變值; 如果環境變數不存在,則建立
putenv("TEST");
→ 環境變數被清空 (TEST = NULL)
- 環境表入口:
extern char **environ;
下面的程式輸出什麼?為什麼?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
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<g_len; c++) {
if (opt == g_handler[c].opt) {
g_handler[c].handler(name, value);
break;
}
}
return 0;
}
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
問題:進行引數 和 環境變數 對程式意味著什麼?