【Linux内核揭秘】深入理解命令行参数和环境变量

文章目录

命令行参数

什么是命令行参数

形如这样的命令后面带的选项就是命令行参数。

首先我们要了解一下命令行参数的原理。

我们知道像ls,mkdir,touch等等这些命令,都是用C语言写的可执行程序,所以必定会有main函数,我们以前学习C语言的时候也接触过一种main函数内部是传递参数的,学习C语言的时候,很难理解这些参数是什么意思,是因为这些参数是系统层面的,而不是语法层面的。

我们要理解命令行参数就需要先解决main函数的参数的问题。

main函数的参数

cpp 复制代码
 int main(int argc,char *argv[])

上面这两个就是main函数的参数了,我们来尝试打印main函数的参数,因为argv对应的是字符串数组,所以我们尝试来打印一下这个数组。

cpp 复制代码
#include<stdio.h>
int main(int argc,char *argv[])
{
  int i=0;
  printf("argc=%d\n",argc);
  for(i=0;i<argc;i++)
  {
    printf("argv[%d]=%s\n",i,argv[i]);
  }
  return 0;
}

可以看见数组当中只有一个元素,假设我们带点选项:

这里我们空格隔开的字符串一共有4个对应的数组元素也是四个,那么这样有什么用呢?

这里展示一个样例,就可以知道这个命令行参数有什么用了。

用下面的代码来简单模拟一下命令行参数的机制:

cpp 复制代码
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[])
{
  if(argc!=2)
  {
    printf("Usage:code opt\n");
  }
  if(strcmp(argv[1],"-opt1")==0)
  {
    printf("功能1\n");
  } 
  if(strcmp(argv[1],"-opt2")==0)
  {
    printf("功能2\n");
  } 
  if(strcmp(argv[1],"-opt3")==0)
  {
    printf("功能3\n");
  }
  return 0;
}

可以看见运行结果:

每个选项都可以实现一种功能。

命令行参数存在的意义:同一个程序可以根据命令行参数,根据选项的不同,表示出不同的功能。

但是问题又来了,main函数是程序执行的入口,但是main函数的参数是谁传进来的呢?

首先我们输入上面这个命令的时候,根据上面所知道的,这其实是一个字符串,然后这些字符串首先会被shell拿到,被shell拿到之后,会根据空格打散形成一张表argv和元素个数argc

由于命令行启动的程序的父进程都是shell,所以命令行启动的命令都是shell的子进程,子进程的PCB还有大多数属性都是继承的父进程的,所以子进程也看得到这个表,所以main函数的参数就被这样传进来了。

这个表的结尾是NULL。

环境变量

什么是环境变量

其实上面讲到的main函数的参数并不全,要说全的话,main函数的参数还有一个env,也是一个char*的数组:
main函数:

cpp 复制代码
 int main(int argc,char *argv[],char *env[])

这才是main函数参数的全部,首先我们找到这张表的结尾是NULL,我们来打印这张表看看,第三个参数就是环境变量。
打印环境参数表:

cpp 复制代码
#include<stdio.h>
int main(int argc,char *argv[],char *env[])
{
  int i=0;
  for(i=0;env[i]!=NULL;i++)
  {
    printf("env[%d]:%s\n",i,env[i]);
  }
}
cpp 复制代码
XDG_SESSION_ID=2654
HOSTNAME=hcss-ecs-e091
TERM=xterm
SHELL=/bin/bash
HISTSIZE=10000
SSH_CLIENT=125.66.243.232 45509 22
SSH_TTY=/dev/pts/0
USER=newuser
LD_LIBRARY_PATH=:/home/newuser/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
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=01;05;37;41: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:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=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:*.jpg=01;35:*.jpeg=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:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/newuser
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/newuser/.local/bin:/home/newuser/bin
PWD=/home/newuser/lesson12
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/home/newuser
LOGNAME=newuser
SSH_CONNECTION=125.66.243.232 45509 192.168.6.60 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/1000
HISTTIMEFORMAT=%F %T newuser 
_=./proc
OLDPWD=/home/newuser

可以看见系统中有很多环境变量,我们不打印env会更清晰:

这里展示部分:

所有环境变量都是通过key对应value来表示的=左边是key,=右边是value,这种kv方式构建的具有全局属性的变量叫做全局变量。

env这张表会一一对应的指向对应的环境变量。
说了这么多,那什么是环境变量?---在 Linux 中,环境变量是用于在操作系统和程序之间传递配置信息的一种机制。环境变量以键值对的形式存在,并在系统或用户会话中定义,用于存储与系统配置、应用程序执行以及用户偏好相关的信息。

常见的环境变量

PATH

PATH:

为什么我们能直接运行系统写好的命令,也就是程序,为什么我们运行我们的程序的时候需要在前面加上./

首先我们先来查看一下PATH这个环境变量,查看环境变量的第一种方法是在代码中遍历整个环境变量表,第二种就是利用echo来查看,但是不能echo PATH因为这样系统会将其识别为一个字符串,需要在PATH前面加上一个$符号,系统才会将其识别为一个变量。

PATH下是一系列路径,不同路径之间用:隔开。

现在回到刚刚的问题,为什么系统知道自己的程序在哪,但是不知道我们的程序在哪?因为shell在登录的时候,有一个环境变量PATH告诉shell你应该到哪里去找,所以系统知道自己的程序在哪里,那我们是否可以像系统这样不加./呢,答案是可以的。

方法1:将我们的可执行程序拷贝到usr/bin目录下

方法2:给环境变量PATH添加一个新的路径

我们说说方法2:

首先不可以这样:

cpp 复制代码
PATH=可执行文件所在路径

这样做直接将原本系统的PATH给直接覆盖了,所以我们应该在以前的PATH下追加上当前路径。

像这样:

cpp 复制代码
PATH=$PATH:可执行程序所在路径

可以看到环境变量就加好了,但是我们会发现,当我们退出系统时,还是运行不了自己的文件,原因是因为,每次在登录时,shell都要根据配置文件来更新PATH,我们只是在内存临时写入了环境变量,重新启动系统时,配置文件还是没变,所以要我们重新启动时还是能运行自己的程序,需要在配置文件中添加上我们的对应路径。

这两个文件就是我们对应的PATH的配置文件,这个目录是在home当中,这些都是隐藏文件,需要用ls -al才能查看到。

我们进入到第一个文件当中:

将红框上面的那句注释掉改成下面注释掉的就好了,其实就是在原本的路径上加上了我们自己相加的路径而已。

像这样配置文件就改好了。

HOME


HOME 环境变量在 Linux 系统中用于指定当前用户的主目录路径。它的值通常是 /home/username,其中 username 是登录用户的用户名。例如,如果用户的用户名是 alice,那么 HOME 的值通常是 /home/alice

不同用户对应的HOME变量是不同的,刚登录上系统时,当前目录就是家目录HOME。

SHELL

SHELL 环境变量在 Linux 系统中表示当前用户默认使用的命令行解释器(Shell)的路径。这个变量的值通常是指向用户首选 Shell 程序的绝对路径,比如 /bin/bash/bin/zsh、或 /bin/sh 等。

PWD

PWD环境变量保存当前路径

除了echo这种查询方式还有什么查询方式吗?---答案是有的,用函数来查。

有一个函数叫getenv,这个函数可以环境变量,我们来掩饰一下。

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[],char *env[])
{
  printf("PWD:%s\n",getenv("PWD"));
  return 0;
}

可以看见也可以查看当前路径。

OLDPWD

OLDPWD 环境变量在 Linux 系统中表示上一次工作目录的路径。当用户在终端中更改目录时(使用 cd 命令),系统会将当前目录的路径存储在 OLDPWD 中。这样,用户可以快速返回之前的目录。

平时我们cd -就是通过这个环境变量来实现的。

本地变量

平时我们肯定这样干过。

这样在命令行上设置变量,这样设置的是环境变量吗?

可以看见这样其实也是可以用echo去查的。

其实这是本地变量,而不是环境变量。

用一张图来理解什么是本地变量什么是环境变量:

其实在bash进程中形成了三张表,还有一张是本地变量表。

shell除了维护环境变量表还会维护本地变量表,shell会在自己内部malloc一段空间,然后将诸如上面的"i=1"这样的字符串存在malloc出来的这段空间中,然后查找的时候shell会根据=的前后去匹配这个变量

如何将本地变量转换成环境变量呢?

有一个命令是export可以将本地变量设置为环境变量,从上面的表可以看出,将本地变量设置为环境变量的本质其实是将本地变量表中指向的字符重新连接到env\[\]上,就这么简单

还有一个命令是取消环境变量是unset,是取消设置环境变量。

总结

在 Linux 中,命令行参数和环境变量作为系统和应用之间的桥梁,提供了灵活且高效的配置和交互方式。通过理解这些机制的内部原理,不仅可以更深入地掌握 Linux 系统的工作方式,还可以优化脚本编写和应用配置的能力。在日常使用中,充分利用环境变量和命令行参数,能够大幅提高工作效率,打造出更加符合需求的操作体验。希望这篇文章能帮助你更好地理解和运用这些基础概念,迈向更高效的 Linux 使用之路!

相关推荐
2501_915106324 分钟前
iOS 软件测试工具性能监控、日志分析 KeyMob、Instruments等
android·ios·小程序·https·uni-app·iphone·webview
JZC_xiaozhong9 分钟前
OA调价审批后,采购调价单如何自动同步到ERP?解决漏录错价难题
大数据·linux·服务器·前端·数据库·数据孤岛解决方案·数据集成与应用集成
ljs64827395112 分钟前
Linux 实用命令:环境变量、文件传输、压缩解压、跨服务器传文件
linux·运维·服务器
__Witheart__37 分钟前
lunch选择的版型与版型对应的配置文件
android·linux
A小调的码农1 小时前
给垃圾平板“一生E本” 装新系统—————Armbian 编译 KYX T7Y (RK3326) 踩坑全记录
linux·嵌入式硬件
ljs6482739511 小时前
Linux 网络常用命令与端口基础详解
linux·网络·php
蓝狐社1 小时前
一张被低估的芯片版图——中兴通讯
运维·服务器
网络小白不怕黑1 小时前
13.SSH服务相关配置
服务器·网络·ssh
Jtti1 小时前
站群服务器多IP能不能分散DDoS攻击流量?
服务器·tcp/ip·ddos
qq_163135751 小时前
Linux 判断是否安装 Conda / Miniconda 完整方法
linux