【Linux】进程概念 —— 环境变量与命令行参数

目录

环境变量

一.概念

二.性质

三.实操

0.常见的环境变量

1.查看环境变量的方法

2.设置环境变量

3.环境变量的组织方式

4.在程序中打印环境变量的三种方式

四.环境变量为什么拥有全局属性

五.如何在当前程序添加环境变量

main函数的命令行参数

一.main函数的前两个参数

1.本质是什么

2.具体怎么用


环境变量

一.概念

环境变量一般指在操作系统中来指定操作系统运行环境的一些参数

如:C/C++程序在链接动静态库的时候,这些库的路径在哪里,我们是不需要担心的

如:在Linux下输入指令,本质就是在运行进程,而我们在运行自己的进程时是需要带路径的,指令则直接输入即可,这都是因为在系统中有环境变量导致的,系统根据环境变量自动的就去找到了路径

以下的一些操作用环境变量PATH举例

二.性质

环境变量具有全局性

全局性的本质:

子进程的环境变量都是从父进程来的

所有的环境变量都会被子进程继承

main函数的父进程是bash,而bash中的是从操作系统中来的

更形象的可以理解为,以bash为一颗多叉树向下由子进程继承,则所有进程都会有

普通变量和环境变量的差别:

本质就是环境变量具有全局性,而普通变量没有

普通变量 = 局部变量

环境变量 = 全局变量

定义普通变量:普通变量名=内容

定义环境变量:export 环境变量名=内容

三.实操

0.常见的环境变量

PATH:指定命令的搜索路径

HOME:指定用户的主工作目录

SHELL:当前shell它的值通常是/bin/bash

1.查看环境变量的方法

echo $环境变量名称

例如:echo $PATH

PATH环境变量用冒号做分隔,每一个冒号后都是一个新的路径

env:查看所有环境变量

set:查看所有变量

unset: 删除环境变量

2.设置环境变量

这里设置环境变量既有设置也有修改

环境变量的设置与修改都仅限于本次登录

因为环境变量具有全局性,每一个子进程都会继承父进程的环境变量,所以如果只是修改当前的环境变量目录的话,也就是只修改了bash,每一次登录就都意味着操作系统要新创建一个bash,bash的环境变量也是由操作系统继承下来的,所以如果想要永久修改环境变量的话,就要修改系统的配置文件。(但是强烈不建议这么做,以防污染原来的系统)

设置新的环境标量一定要有export,修改的话可有可无

export 环境变量=要配置的环境变量

例如:export PATH=$PATH:新增路径

3.环境变量的组织方式

【Linux】进程概念 —— 环境变量与命令行参数_第1张图片

以环境变量表的形式组织起来,最终每个进程都会收到一张环境表

环境变量表的本质就是一个字符指针数组,这是一个数组,数组的每个元素存放的是字符串首地址,最终这个字符串以\0结尾,并且这个字符指针数组结尾是NULL

4.在程序中打印环境变量的三种方式

通过main函数中的三个参数之一:char*env[]就可以打印出环境表

int main(int argc, char* argv[], char*env[])
{
  printf("---------------------------\n");
  //查看当前所有的环境变量
  int i = 0;
  for(; env[i]; i++)
  {
    printf("%s\n",env[i]);
  }
  printf("---------------------------\n");
  return 0;
}

或者通过系统的environ二维指针来打印出环境表

#include

int main()
{
  extern char** environ;
  int i = 0;
  for(; environ[i]; i++)
  {
    printf("%s\n",environ[i]);
  }
  return 0;
}

【Linux】进程概念 —— 环境变量与命令行参数_第2张图片

查看某一个环境变量:getenv函数

【Linux】进程概念 —— 环境变量与命令行参数_第3张图片

#include
#include


int main()
{
  printf("%s\n",getenv("PATH"));
  return 0;
}

四.环境变量为什么拥有全局属性

思考: 环境变量是如何拥有全局属性的呢? 子进程是如何继承父进程的环境变量的?

父进程在创建子进程时, 子进程的代码和数据以写时拷贝的形式拷贝到子进程

同时, 父进程的命令行参数与环境变量也就拷贝到了子进程中, 从而使子进程继承了父进程的环境变量

注意: 进程替换时, 被替换的进程(通常是子进程)的环境变量是不会被替换的

例如: 我在Shell上编写了一个mytest.c程序, 并且编译成mytest可执行文件, 此时, mytest这个可执行文件如果直接执行, 继承的是Shell的环境变量(也就是系统的环境变量), 如果这时, 我自己实现了一个miniShell, 并且添加了MYVAL=666这样的环境变量, 在运行miniShell下执行mytest, 此时miniShell会fork出一个子进程(这时就会有虚拟地址空间的写时拷贝, 同时环境变量也被拷贝到了子进程), 通过进程替换的方式, 将子进程替换为mytest进程, 子进程的环境变量不会被替换, 所以执行的mytest的环境变量也就是继承了miniShell的

五.如何在当前程序添加环境变量

在Shell中, 我们可以通过export命令的方式去添加一个环境变量, 那么, 在一个程序中, 如何添加环境变量呢?

系统调用: int putenv(char* string)

int res = putenv("MYVAL=666");

如果添加成功返回0, 添加失败返回非0, 并且会设置errno为相应的数值

【Linux】进程概念 —— 环境变量与命令行参数_第4张图片

特别注意

在添加环境变量时如果是给putenv传入一个常量字符串最好, 但是一般我们写的程序需要运行起来之后由我们输入添加什么字符串, 所以通常在编写程序时, 我们是不知道具体的要添加哪一个环境变量的

所以一般我们都是以这种形式去添加:

char buffer[64];//最好定义为全局的, 原因之后再说
scanf("%s", buffer);
putenv(buffer);

//以上这只是举例而已
//在Shell中真正的用法需要命令行参数argv的介入, 但原理都是相同的

 解释一下为什么buffer最好是全局的, 在putenv添加环境变量时, 其实只是把字符串的首地址添加进去了, 然后通过首地址就能找到这个字符串buffer, 但是如果buffer被覆盖或者被无效化之后, 这个添加的全局变量也就没有了, 所以必须保证被添加的环境变量的指针指向的空间是一直有效且不会被修改的

main函数的命令行参数

一.main函数的前两个参数

1.本质是什么

char argc与char* argv[]是命令行参数

#include

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

【Linux】进程概念 —— 环境变量与命令行参数_第5张图片本质:

【Linux】进程概念 —— 环境变量与命令行参数_第6张图片

2.具体怎么用

#include
#include

int main(int argc, char* argv[])
{
  if(argc != 2)
  {
    printf("必须带有选项\n");
    return 0;
  }
  if(strcmp(argv[1],"-a")==0)
  {
    printf("这是功能一\n");
  }
  else if(strcmp(argv[1],"-b")==0)
  {
    printf("这是功能二\n");
  }
  return 0;
}

【Linux】进程概念 —— 环境变量与命令行参数_第7张图片

 这本质就是我们在Linux命令行下输入的命令,每个命令带不同的选项执行不同的功能

你可能感兴趣的:(Linux,linux)