Linux:环境变量

目录

一、命令行参数

二、环境变量

1.认识常见的环境变量

2.创建环境变量

3.环境变量表

4.利用环境变量

5.本地变量

6.bash进程的环境变量


一、命令行参数

        在介绍环境变量之前,要先介绍命令行参数这一概念。

        我们所写的main函数,一般参数都是void,但是main函数是可以有形参参数的,如下。

int main(int argc,char* argv[])
{
    return 0;
}

        第二个参数的类型为指针数组,指针数组的元素可以有两种,一种就是char*,还有一种就是字符串

        这两个参数之间有一个关系:数组argv的大小等于argc的值

        既然如此,编写源文件myprocess.c如下。

int main(int argc,char *argv[])
{
  for(int i = 0; i < argc;++i)
  {
    printf("argv[%d]:%s\n",i,argv[i]);
  }
  return 0;
}

        可执行程序命名为myprocess,输出结果如下。

[euto@VM-4-13-centos 24922]$ ./myprocess 
argv[0]:./myprocess

        如果执行的命令是下面这样的,发现打印结果又会有所不一样。

[euto@VM-4-13-centos 24922]$ ./myprocess  -1
argv[0]:./myprocess
argv[1]:-1
[euto@VM-4-13-centos 24922]$ ./myprocess  -w -2 -2
argv[0]:./myprocess
argv[1]:-w
argv[2]:-2
argv[3]:-2

        这个过程是如何实现的呢?其实,在命令行中,

[euto@VM-4-13-centos 24922]$ 

        这一行,本质是由bash这个程序运行了一句printf打印的结果。而我们输入的命令,也是被bash作为一个字符串保存起来。

"./myprocess  -w -2 -2"

        随后,bash把这个字符串按照空格分隔成多个小字符串

"./myprocess"
"-w" 
"-2"
"-2"

        然后,用一个数组把这些个小字符串的首字符地址存起来。这个数组就是char* argv[],数组的大小就是argc,值得注意的是,这个数组的尾元素一定是NULL。

        这个数组称为命令行参数表

        当程序myprocess启动的时候,父进程(一般是bash)把argc和argv传参给main函数,于是,就有了上面的打印结果。

        因为数组尾为NULL,main函数如果下面这样写,得到的结果是一样的。

[euto@VM-4-13-centos 24922]$ cat myprocess.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
  for(int i = 0; argv[i];++i)
  {
    printf("argv[%d]:%s\n",i,argv[i]);
  }
  return 0;
}
[euto@VM-4-13-centos 24922]$ ./myprocess -a -b -c -1 -2
argv[0]:./myprocess
argv[1]:-a
argv[2]:-b
argv[3]:-c
argv[4]:-1
argv[5]:-2

        思考,bash分割输入命令的目的何在。现在,假设有这样一个场景,要求程序可以根据输入命令的不同,显示不同的输出结果。

//要求实现3种功能。-1 -2 -3三个选项对应三种功能
//如果输入非-1 -2 -3,则提示正确的输入格式。
int main(int argc,char* argv[])
{
  if(argc != 2)
  {
    printf("Usage\n\t:%s -[number=1/2/3]\n",argv[0]);
    return 1;
  }
  if(strcmp(argv[1], "-1") == 0)
  {
    printf("function 1\n");
  }
  else if(strcmp(argv[1],"-2") == 0)
  {
    printf("function 2\n");
  }
  else if(strcmp(argv[1],"-3")==0)
  {
    printf("function 3\n");
  }
  else{
    printf("unkonwn function\n");
  }
}

        运行结果如下所示。

[euto@VM-4-13-centos 24922]$ ./myprocess 
Usage
	:./myprocess -[number=1/2/3]
[euto@VM-4-13-centos 24922]$ ./myprocess -1
function 1
[euto@VM-4-13-centos 24922]$ ./myprocess -2
function 2
[euto@VM-4-13-centos 24922]$ ./myprocess -3
function 3
[euto@VM-4-13-centos 24922]$ ./myprocess -6
unkonwn function

        如果你对Linux的命令比较熟悉,那么这是否有点眼熟,像下面的操作。

[euto@VM-4-13-centos 24922]$ ls
Makefile  myprocess  myprocess.c
[euto@VM-4-13-centos 24922]$ ls -l
total 20
-rw-rw-r-- 1 euto euto   85 Sep 22 19:15 Makefile
-rwxrwxr-x 1 euto euto 9600 Sep 22 20:06 myprocess
-rw-rw-r-- 1 euto euto  652 Sep 22 20:05 myprocess.c
[euto@VM-4-13-centos 24922]$ ls -a
.  ..  Makefile  myprocess  myprocess.c

        于是,可以总结,指令的选项实现不同的功能,其实是bash把输入的字符串内容分割后传参给指令所对应程序的main函数,选项本质上就是命令行参数


        实战,用命令行参数的方式实现一个加减乘除计算器。

int main(int argc,char* argv[])
{
  
  if(argc != 4)
  {
    printf("Usage\n\t:%s -[add|sub|mul|div] x y\n",argv[0]);
    return 1;
  }
  int x = atoi(argv[2]);
  int y = atoi(argv[3]);
  if(strcmp(argv[1], "add") == 0)
  {
    printf("%d + %d = %d\n",x,y,x+y);
  }
  else if(strcmp(argv[1],"sub") == 0)
  {
    printf("%d - %d = %d\n",x,y,x-y);
  }
  else if(strcmp(argv[1],"mul")==0)
  {
    printf("%d * %d = %d\n",x,y,x*y);
  }
  else if(strcmp(argv[1],"div")== 0)
  {
    printf("%d / %d = %d\n",x,y,x/y);
  }
  else{
    printf("unkonwn function\n");
  }
}
[euto@VM-4-13-centos 24922]$ ./myprocess sub 3 5
3 - 5 = -2
[euto@VM-4-13-centos 24922]$ ./myprocess mul 3 5
3 * 5 = 15
[euto@VM-4-13-centos 24922]$ ./myprocess 8 2
Usage
	:./myprocess -[add|sub|mul|div] x y
[euto@VM-4-13-centos 24922]$ ./myprocess div 8 2
8 / 2 = 4

二、环境变量

  • 环境变量不是只有一个,是有多个,一般是十几个左右,彼此之间没有直接关联。
  • 环境变量,一般是系统内置的,用作特殊用途的变量。
  • 重新理解变量,传统上,语言的函数会定义变量,正在运行的程序也可以定义变量。变量本质上就是两种属性,名称和内存空间,因此,操作系统只要将一个事物赋予名称和内存空间,也可以称为变量!!!这就是环境变量。

1.认识常见的环境变量


        在我们运行一个可执行程序的时候,有两种指令格式都可以成功运行。

[euto@VM-4-13-centos 24922]$ ll
total 20
-rw-rw-r-- 1 euto euto   85 Sep 22 19:15 Makefile
-rwxrwxr-x 1 euto euto 9696 Sep 22 20:30 myprocess
-rw-rw-r-- 1 euto euto 1261 Sep 22 20:30 myprocess.c
//方式1
[euto@VM-4-13-centos 24922]$ ./myprocess 
Usage
	:./myprocess -[add|sub|mul|div] x y
//方式2
[euto@VM-4-13-centos 24922]$ /home/euto/linux/24922/myprocess 
Usage
	:/home/euto/linux/24922/myprocess -[add|sub|mul|div] x y

        这两种格式本质上都要求使用者把可执行程序的路径标识出来,否则,bash无法识别。

[euto@VM-4-13-centos 24922]$ myprocess
-bash: myprocess: command not found

        那么,像lspwd等等指令也是可执行程序,为什么可以直接运行,不用标识路径。尽管标识了路径,也可以运行。

[euto@VM-4-13-centos linux]$ which ls
alias ls='ls --color=auto'
	/usr/bin/ls
[euto@VM-4-13-centos linux]$ /usr/bin/ls
24912  24915  24918  24919  24921  24922  24925  README.md
[euto@VM-4-13-centos linux]$ which pwd
/usr/bin/pwd
[euto@VM-4-13-centos linux]$ /usr/bin/pwd
/home/euto/linux

        这是因为在系统中,存在一个全局的环境变量PATH,它的内容如下:

[euto@VM-4-13-centos linux]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/euto/.local/bin:/home/euto/bin

        它的内容是被 ':' 分割成的一个个路径。那么这些路径的意义是什么。当在命令行运行可执行程序后,会率先在PATH保存的路径去查找,比如ls、pwd/usr/bin这个路径下,而PATH保存了这个路径,因此,ls、pwd这样的指令就可以直接在命令行中运行了。

        现在,我们想让当前目录下用户自己实现的可执行程序也像ls、pwd那样直接执行,就有两种做法。

        1.把当前可执行程序文件拷贝到路径/usr/bin下面,不过,这种做法很危险,会污染库。

        2.推荐第二种做法,把当前可执行程序的路径保存在PATH变量中。

[euto@VM-4-13-centos 24925]$ pwd
/home/euto/linux/24925
[euto@VM-4-13-centos 24925]$ PATH=/home/euto/linux/24925:$PATH
[euto@VM-4-13-centos 24925]$ echo $PATH 
/home/euto/linux/24925:/usr/local/bin:/usr/bin:/usr/local/sbin
:/usr/sbin:/home/euto/.local/bin:/home/euto/bin

        添加到PATH变量后,执行myprocess可以直接运行程序了。

[euto@VM-4-13-centos 24925]$ myprocess 
Usage
	:myprocess -[add|sub|mul|div] x y

        注意,这里修改PATH变量时,一定要加上$PATH$PATH用来标识PATH原来的值,因为PATH=?是覆盖式写入,加上$PATH会把原来的路径保留下来。

        如果不小心把PATH覆盖了,执行ls等指令发现报错not found,只需要关机重启,PATH会被系统重新初始化的。


        此外,还有其他环境变量。开机后,执行pwd指令,可以查看当前所在路径,切换到其他目录,执行pwd指令,也可以查看到路径,这是因为pwd指令打印的内容是依据一个环境变量PWD

[euto@VM-4-13-centos 24925]$ pwd
/home/euto/linux/24925
[euto@VM-4-13-centos 24925]$ echo $PWD
/home/euto/linux/24925
[euto@VM-4-13-centos 24925]$ cd /
[euto@VM-4-13-centos /]$ echo $PWD 
/

        whoami打印的结果是依据环境变量USER

[euto@VM-4-13-centos /]$ whoami
euto
[euto@VM-4-13-centos /]$ echo $USER 
euto

        当前用户的家目录是依据环境变量HOME

[euto@VM-4-13-centos /]$ cd ~
[euto@VM-4-13-centos ~]$ pwd
/home/euto
[euto@VM-4-13-centos ~]$ echo $HOME 
/home/euto

        查看系统中的全部环境变量使用命令env,环境变量的格式都是Key=Value

[euto@VM-4-13-centos ~]$ env
XDG_SESSION_ID=698629
HOSTNAME=VM-4-13-centos
TERM=xterm
SHELL=/bin/bash
HISTSIZE=3000
·········

2.创建环境变量

        执行指令export Key=Value

[euto@VM-4-13-centos ~]$ export Name=Lenovo
[euto@VM-4-13-centos ~]$ echo $Name 
Lenovo

3.环境变量表

        其实,main函数还有第三个参数,这个参数和argv十分相似,只不过argv保存是命令行参数,而第三个参数名为env保存的是环境变量。

        这个env数组被称为环境变量表

int main(int argc,char* argv[],char* env[])
{
  for(int i= 0;env[i];++i)
  {
    printf("++++++env[%d]->%s\n",i,env[i]);
  }
}

         打印结果如下。

[euto@VM-4-13-centos 24925]$ ./myprocess 
++++++env[0]->XDG_SESSION_ID=698629
++++++env[1]->HOSTNAME=VM-4-13-centos
++++++env[2]->TERM=xterm
++++++env[3]->SHELL=/bin/bash
++++++env[4]->HISTSIZE=3000
++++++env[5]->SSH_CLIENT=116.130.192.236 56739 22
++++++env[6]->OLDPWD=/home/euto/linux
++++++env[7]->SSH_TTY=/dev/pts/0
++++++env[8]->USER=euto
++++++env[9]->LD_LIBRARY_PATH=:/home/euto/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
··················

        整个过程应该是这样,当执行./myprocess后,系统会创建PCB,使其变为一个进程,但是在此之前,myprocess要从main函数开始执行语句,main函数有参数,那么这个参数是由谁来传递?由父进程,一般是bash,bash也是一个程序,在bash程序中已经有了环境变量表

        于是,有了结论,环境变量是可以由子进程继承的。而由于环境变量可以被所有的子进程继承,故环境变量具备了全局属性!!!

        为了验证这个结论,创建一个子进程。

int main(int argc,char* argv[],char* env[])
{
  for(int i= 0;env[i];++i)
  {
    printf("++++++env[%d]->%s\n",i,env[i]);
  }
  pid_t id = fork();
  if(id == 0)
  {
    printf("####################\n");
    for(int i= 0;env[i];++i)
    {
      printf("---------env[%d]->%s\n",i,env[i]);
    }
  }
}

        子进程的环境变量也同样被打印了出来,父子进程之间,代码共享,数据则发生写时拷贝各自私有一份。 

[euto@VM-4-13-centos 24925]$ ./myprocess 
++++++env[0]->XDG_SESSION_ID=698629
++++++env[1]->HOSTNAME=VM-4-13-centos
++++++env[2]->TERM=xterm
++++++env[3]->SHELL=/bin/bash
++++++env[4]->HISTSIZE=3000
++++++env[5]->SSH_CLIENT=116.130.192.236 56739 22
···············
########################
---------env[0]->XDG_SESSION_ID=698629
---------env[1]->HOSTNAME=VM-4-13-centos
---------env[2]->TERM=xterm
---------env[3]->SHELL=/bin/bash
---------env[4]->HISTSIZE=3000
---------env[5]->SSH_CLIENT=116.130.192.236 56739 22
---------env[6]->OLDPWD=/home/euto/linux
---------env[7]->SSH_TTY=/dev/pts/0
---------env[8]->USER=euto
················

4.利用环境变量

        环境变量在实际代码中,有什么作用呢。就用环境变量USER举例,假设程序只想让指定的用户实现功能,如果是其他用户,则提示你没有权限。

        获取环境变量的Value的函数如下。

NAME
       getenv, secure_getenv - get an environment variable

SYNOPSIS
       #include <stdlib.h>

       char *getenv(const char *name);

        编辑源文件内容如下。

int main()
{
  const char* UsrName = getenv("USER");

  if(strcmp(UsrName,"root") == 0)
  {
    printf("您是root用户,您有权限\n");
  }
  else{
    printf("您是非root用户,您没有权限\n");
  }

  return 0;
}

        运行结果如下。

//
[root@VM-4-13-centos 24925]# ./myprocess 
您是root用户,您有权限
//
[euto@VM-4-13-centos 24925]$ ./myprocess 
您是非root用户,您没有权限

5.本地变量

        除了环境变量这个概念,还存在一个概念叫做本地变量。

        创建本地变量的方式和创建环境变量的方式有所不同,在命令行中直接执行Key=Value

[euto@VM-4-13-centos 24925]$ test=localvar
[euto@VM-4-13-centos 24925]$ echo $test
localvar

        执行env是查不到这个变量的,说明它不是一个环境变量。而指令set会把环境变量和当前命令行的本地变量都打印出来,故可以执行set找到这个本地变量。

[euto@VM-4-13-centos 24925]$  set | grep test
test=localvar

        本地变量,区别于环境变量最重要的特性就是不会被子进程继承,即没有全局属性。

6.bash进程的环境变量

        我们在命令行中自定义的一个程序,它的环境变量继承自bash,那么bash的环境变量来自哪里。

        上文有讲过,如果默认环境变量不小心被修改,或者所有环境变量被删除了,我们只需要将主机重启即可。这意味着,系统在启动的时候,会重新初始化环境变量的值。也表明,在磁盘中存储着相应的系统配置文件

//切换到家目录
cd ~
//查看隐藏文件
ll -a

        找到下面这个文件。

-rw-r--r--   1 euto euto   193 Apr  1  2020 .bash_profile
[euto@VM-4-13-centos ~]$ cat .bash_profile 
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin

export PATH
-rw-r--r--   1 euto euto   391 Nov  7  2023 .bashrc
[euto@VM-4-13-centos ~]$ cat .bashrc 
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions
alias vim='/home/euto/.VimForCpp/nvim'
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
alias vim='/home/euto/.VimForCpp/nvim'

        此外还有其他配置文件都设置了环境变量的值,所以环境变量是在系统启动时由配置文件初始化的,后续进程的环境变量都是从bash进程继承而来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值