问题引入
我们先来看一段简单的死循环代码:
int main()
{
while(1)
{
printf("i am running!\n");
sleep(1);
}
return 0;
}
我们将其运行编译并生成为可执行文件 myproc ,当我们要运行它的时候,都得在这个可执行文件前面加一个 ./ 这是为什么?
[liren@VM-8-2-centos process]$ ./myproc
我们再仔细想想以前接触到的一些指令比如说 which、touch 等等命令,它们其实也是一些可执行文件,这个可以用 file 指令验证一下:
那为什么都是可执行文件,我们自己写的 myproc 就要在前面加上 ./ 才能执行呢,而系统中的指令则不用呢?
难道说 /usr/bin/ 这个目录下面有蹊跷?
所以我们试试看把 myproc 也放到这个目录下面,看看能不能直接执行:
居然可以!但是我们要知道的是 /usr/bin 是系统目录,我们一般是最好不要向里面随便放文件,因为我们自己写的代码一般是没有经过测试的,这样子的话会**污染系统当中的 “指令池”** 的!
那除了这样子做,还有什么办法吗?
答案是有的!我们先输入 echo $PATH 观察一下:
[liren@VM-8-2-centos process]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/liren/.local/bin:/home/liren/bin
啊?这一大串是什么?
其实这是一些**绝对路径,linux中每个路径之间用 : 号分开**!
我们在这里可以明显看到 /usr/bin 也在其中,而我们上面的 PATH 其实就是**环境变量,而环境变量中保存的就是当前指令的搜索路径**!
至于这里为什么要加 $ 呢,因为 PATH 相当于 bash 是一个全局变量,所以用 echo 查看的时候要加上 $
下面我们就来介绍一下环境变量!
Ⅰ. 环境变量(environment variables)
1、基本概念
- 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途(比如说确定用户身份、确定主机名等等),在系统当中通常具有 全局特性
- 环境变量是会被子进程继承下去的,这是为了一些应用场景比如说让bash帮忙找指令、身份认证等等
🔴 一般 shell 的默认环境变量放在 ~/.bash_profile
中,这是一个用户级的环境配置文件,每个用户目录下都会具有各自的,在用户每次登录系统时被读取,里面所有命令都会被 shell 执行,包括环境变量的配置命令!
2、常见的环境变量
PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是 /bin/bash
HISTSIZE:当前的命令历史保存数量,用一些方法是可以修改这个数量的
USER:标识当前使用的Linux用户
① 对于PATH:
我们在问题引入那里也说到,将我们自己写的可执行文件放到 /usr/bin/ 目录下虽然也是可以让我们的可执行文件实现指令一样的使用方式,这里我们讲一下另外一种方式,就是将这个可执行文件,这里以 myproc 为例,将 myproc 所处的路径添加到 PATH 的路径中,依旧可以达到这个效果!
格式是这样子的:==新的路径 = 原来的路径 : 要添加的路径 = = ∗ ∗ ,注意如果没有 ∗ ∗ 原来的路径:要添加的路径==** ,注意如果没有 ** 原来的路径:要添加的路径==∗∗,注意如果没有∗∗PATH,那么老的路径会被全部替换成要添加的路径。
[liren@VM-8-2-centos process]$ ll
total 20
-rw-rw-r-T 1 liren liren 74 Dec 12 20:50 makefile
-rwxrwxr-x 1 liren liren 8408 Jan 13 17:19 myproc
-rw-rw-r-- 1 liren liren 1023 Jan 13 17:18 myproc.c
[liren@VM-8-2-centos process]$ pwd
/home/liren/playcode/env/process
[liren@VM-8-2-centos process]$ PATH=$PATH:/home/liren/playcode/env/process/myproc
[liren@VM-8-2-centos process]$ myproc
i am running!
i am running!
^C
[liren@VM-8-2-centos process]$
如果真的不小心将原来 PATH 下的路径都覆盖了,那么原来的系统级命令如 touch 都没办法用了,但是别怕,PATH 既然是变量,意味着它是可以被赋值的,那么最开始的一串的默认路径肯定是 Linux 系统在给你这个用户在配置文件里加载下来的。所以我们直接重新登录即可恢复默认的路径。
但是重新登陆后会发现那些我们新增到 PATH 中的路径都没了,那么我们怎么永久性的保存它们呢?
下面介绍两个方法:
-
修改相关配置文件,但是对小白来说极其不推荐。当系统登录成功后,系统会把各种需要的脚本运行一下,然后我们就看到
echo $PATH
里的内容了。如下图中在用户目录下隐藏的一个文件
.bash_profile
,就会去加载.bashrc
去添加环境变量: -
把程序拷贝到 PATH 下的任何一个路径下。
[liren@VM-8-2-centos process]$ ll total 20 -rw-rw-r-T 1 liren liren 74 Dec 12 20:50 makefile -rwxrwxr-x 1 liren liren 8408 Jan 13 17:19 myproc -rw-rw-r-- 1 liren liren 1023 Jan 13 17:18 myproc.c [liren@VM-8-2-centos process]$ myproc -bash: myproc: command not found [liren@VM-8-2-centos process]$ echo $PATH /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/liren/.local/bin:/home/liren/bin [liren@VM-8-2-centos process]$ sudo cp myproc /usr/bin/ #将myproc放到PATH的一个路径下 [liren@VM-8-2-centos process]$ myproc i am running! i am running! i am running! i am running! ^C [liren@VM-8-2-centos process]$
② 对于HOME:
根本原因是因为 Linux 系统中有一个环境变量 —— HOME,它默认表明当前用户登录时所处的默认路径,当然它在系统中也有配置的。我们从上图可以看到 liren
用户中 HOME
保存的是 /home/liren
;而 root
用户中 HOME
保存的是 /root
。
这就是为什么我们的指令 cd ~
可以在任意位置回到当前用户的主目录下的原因!因为系统将 ~
标识成当前用户的主目录也就是HOME!
③ 对于USER:
USER标识当前使用的Linux用户,这主要用于一些场景如身份认证,比如说权限问题,为什么说不是文件的拥有者就打不开该文件呢?因为系统每次在执行指令前会先比较一下当前文件的拥有者、所属组是否符合当前使用的Linux用户(因为都是字符串,可以用 strcmp 进行字符串对比),符合的话才能进行对应的操作!
3、查看环境变量方法及相关命令
-
echo $NAME:NAME是环境/本地变量的名称,查看 NAME 变量的内容。(如PATH、USER变量等)
-
env:显示所有的环境变量。
-
set:查看本地定义的shell变量和环境变量。
-
export:设置新的环境变量。
-
unset:清除设置的环境变量。
-
变量名=变量的值(其中变量的值都被认为是字符串):定义一个本地变量,如 myval=1234567 ,可以用 echo $myval 查看
👺 注意:环境变量是具有全局属性的,而本地变量只有局部属性(且只会在当前进程也就是bash内有效),相当于C语言中的全局变量和局部变量的关系(下面会解释)
下面我们来细讲一下这些命令以及特性:
首先 echo $NAME
就不用多讲了,上面已经演示了多次了!
env
指令可以打印出系统中所有的环境变量,可以配合 grep
进行操作,如下图:
接下来我们进行一个操作,也就是上述的第六点,创建一个本地变量 myval
,并用 env
去查找它,会发现它并没有在环境变量里面。
而如果我们用 set
命令去查看 myval
呢?答案是可以的,因为 set
命令用于查看本地变量包括环境变量,也就是说,不用 grep
筛选一下的话,那么会打印出很多变量!关系如下图:
这也可以看出来本地变量和环境变量是有区别的,我们继续看。
我们写一个程序观察一下(代码中的 getenv() 后面会讲):
#include <stdio.h>
#include <stdlib.h>
#define MY_ENV "myval"
int main()
{
// getenv获取MY_ENV的环境变量,若不存在则返回null,存在则返回对应的值
char* myenv = getenv(MY_ENV);
if(myenv == NULL)
{
printf("%s not found.", MY_ENV);
return 1;
}
printf("%s=%s\n", MY_ENV, myenv);
return 0;
}
运行结果是没有找到,说明什么?myval
不被当前的子进程 myproc 所认识,也就是说 myval
这个本地变量只能被父进程也就是 bash 所认识而已,不会被子进程继承下来。
下面我们用 export
将 myval
变成环境变量,再来试一遍:
可以看见 myval
变成环境变量后,既能用 set
观察到,执行我们上述代码也能拿到它的环境变量的值,说明环境变量是可以被子进程 myproc 继承下来的!
接下来我们再用一个 unset
指令,将 myval
删除,并用 echo
显示出来看看:
最后来看一个问题:
???后知后觉,是不是有点奇怪,明明 echo
也是一个指令呀,使用它的时候也是会创建子进程的,但是为什么它就可以接收到本地变量 myval
,我们上面不是说子进程不会继承到本地变量的吗 ?
这里想说的是 echo
当然是命令,echo
在执行的时候肯定是 bash 的子进程里,那么感觉它作为子进程却能继承本地变量的原因是:我们上面说的是 “ 大部分 ” 命令,而其中像 echo
、export
、set
、env
等命令,我们一般称之为 内建命令,可以理解为 shell 程序内部的一个函数,也就是说 shell 在执行命令时,如果是内建命令,那么它直接调用内建命令对应的方法,如果不是内建命令,那么就会 fork 子进程。
Ⅱ. 命令行参数
1、argc 和 argv[]
相信我们在学C/C++的时候有见过这两个命令行参数,没见过的话也没事,我们这次将它们一次性搞懂!
int argc是命令行参数的个数;char* argv[]是指针数组,数组里有几个有效元素是由 argc
确定,所以 main 函数的前两个参数用来记录的是我们在命令行上传入的参数,我们称这两个参数为 命令行参数。
我们先写一个程序(注意下面程序编译的时候需要特别指定 -std=c99 才能支持):
#include <stdio.h>
int main(int argc, char* argv[])
{
for(int i = 0; i < argc; ++i)
{
printf("argv[%d]->%s\n", i, argv[i]);
}
/* 或者这样子写,因为argc的最后一个元素是NULL for(int i = 0; argc[i]; ++i) { printf("argv[%d]->%s\n", i, argv[i]); } */
return 0;
}
可能我们会疑惑,这有什么作用??当然,平时我们在 windows 下是感受不出来的,现在我们多输入这个选项试一试:
有没有发现什么!这像不像我们在输入指令的同时输入不同的选项!
是的!linux中指令的多选项就是来自于命令行参数,而其中这些选项的传参由shell和操作系统来完成!比如说 ls -a -l
或者 ls -al
,我们可以在程序中运用 strcmp 函数与每一个选项进行对比判断,最后决定这个指令的结果。
其实在 windows 也是有的,只不过我们很少用,比如说关机指令 shutdown 就是配有多种选项,同样也是利用命令行参数来实现的!这就是命令行参数最大的价值!
在C语言里,我们学习函数栈帧时,说过 main() 是被 __tmainCRTStartup() 调用的,tmainCRTStartup() 最后是被操作系统调用的,其中 main 函数的参数是在 __tmainCRTStartup() 调用 main 函数时就传入了,Linux 下也是如此,
2、第三个参数env[]
==char env[]==* 是 main 函数的第 3 个参数,它和第 2 个参数的类型一样都是**指针数组。但是 env 的每个元素是环境变量。换言之,我们把环境变量的路径作为字符串,数组也是以 NULL 结尾的*,用 char env[] 这样的字符指针数组,依次指向不同的环境变量,我们就可以通过数组传参的方式,把环境变量传递给当前程序,当前程序运行后成为进程,也就意味着进程拿到了环境变量。
#include <stdio.h>
int main(int argc, char* argv[], char* env[])
{
for(int i = 0; env[i]; ++i)
{
printf("env[%d]->%s\n", i, env[i]);
}
return 0;
}
通过上述代码,我们就可以拿到了当前系统的所有环境变量!
Ⅲ. 获取环境变量的方法
1、通过命令行参数的第三个参数 env
这种方法我们在上面已经讲过了,我们着重来研究一下后两种!
2、通过函数 getenv()
其实我们在上面讲环境变量时候已经使用过 getenv() 了,来看看下面的代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* env = getenv("PATH");
if(env != NULL)
printf("%s=%s\n", "PATH",env);
else
return 1;
return 0;
}
3、通过第三方变量 environ
C语言为我们提供了一个第三方变量 environ ,它是一个二级指针,libc
中定义的全局变量 environ
指向环境变量表,environ
没有包含在任何头文件中,所以在使用时要用 extern
声明。
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以NULL结尾的环境字符串
下面代码获取环境变量:
#include <stdio.h>
#include <unistd.h>
int main()
{
extern char** environ; // 最好要声明一下
for(int i = 0; environ[i]; ++i)
{
printf("%d:%s\n", i, environ[i]);
}
return 0;
}
今天的文章环境变量 命令行_查看环境变量的命令分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/84030.html