Linux 下命令行参数和环境变量

Linux 下命令行参数和环境变量

  • 命令行参数
    • 为什么要有命令行参数
    • 谁可以做到
    • 结论
  • 环境变量
    • 一些现象
    • 查看环境变量
    • 添加环境变量
      • 添加内存级环境变量
      • 永久有效
    • 其他环境变量
      • HOME
      • PWD
      • SHELL
      • HISTSIZE
    • 自定义环境变量
      • 定义
      • 取消
    • 本地变量
    • 整体理解环境变量
      • 环境变量的组织方式
      • Linux 代码获取环境变量
        • 方式一
        • 方式二
        • 方式三
      • 理解
      • 测试本地变量和环境变量

命令行参数

我们平时写 C 语言代码时, main() 函数是必须要写的;虽然我们一般并不会给 main() 函数带上参数,但 main() 函数的确是 有参数的

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

先来解释:
argv 是个 指针数组 ,它本质上是一个 数组 ,里面都是 char* 类型的指针
argc 是指 argv元素的个数

咱们先来做一次测试,看看 argv 里到底有什么 :

// test.c 文件
#include <stdio.h>
#include <unistd.h>int main(int argc, char* argv[])
{for (int i = 0; i < argc; ++i){printf("argv[%d] -> %s\n", i, argv[i]);}return 0;
}

编译为 mytest 可执行文件,在 命令行 上运行如下指令:

./mytest
./mytest -a
./mytest -a -b
./mytest -a -b -c
./mytest -a -b -c -d

结果如下:

[root@localhost command_line_parameter]$ ./mytest
argv[0] -> ./mytest
[root@localhost command_line_parameter]$ ./mytest -a
argv[0] -> ./mytest
argv[1] -> -a
[root@localhost command_line_parameter]$ ./mytest -a -b
argv[0] -> ./mytest
argv[1] -> -a
argv[2] -> -b
[root@localhost command_line_parameter]$ ./mytest -a -b -c
argv[0] -> ./mytest
argv[1] -> -a
argv[2] -> -b
argv[3] -> -c

一目了然 argv 里面是什么,显然是将输入的指令字符串以空格为界限切开,分别存进 argv 元素所指的空间里,但不论有几个元素, argv 结尾的元素都是 null

切割原理也很简单,无非就是将 空格 替换为 '\0' 即可,如此一个长字符串就变为多个子串

那这有什么意思呢?
请用上面的方法验证下面的代码:

// test.c 文件
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main(int argc, char* argv[])
{if (argc != 2){printf("Usage: %s -[a, b, c, d]\n", argv[0]);return 1;}if (strcmp(argv[1], "-a") == 0)printf("It is function1\n");else if (strcmp(argv[1], "-b") == 0)printf("It is function2\n");else if (strcmp(argv[1], "-c") == 0)printf("It is function3\n");else if (strcmp(argv[1], "-d") == 0)printf("It is function4\n");else printf("Nothing!!!\n");return 0;
}

验证结果是否感觉有些似曾相识?没错,就是指令后带选项罢了,类似 ls -l 等等

为什么要有命令行参数

命令行参数本质是 交给程序不同的选项,从而定制出不同的功能;就像是 Linux 的指令携带有自己的选项一样

目前遇到的许多命令,都是 C 语言写的

谁可以做到

验证下面的代码就得知:父进程的数据,默认能被子进程看到并访问

#include <stdio.h>
#include <unistd.h>
#include <string.h>int g_val = 100;int main()
{printf("It is a process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);sleep(5);pid_t id = fork();if (id == 0){// childwhile (1){printf("It is a child process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);sleep(1);}}else {// parentwhile (1){printf("It is a parent process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);sleep(1);}}return 0;
}

此时我们观察第一行打印数据,其父进程,查询后会发现就是 bash 进程,也就是说, bash 进程是所有在命令行下启动的进程的父进程

所以我们平时输入的指令字符串是默认交给父进程 bash 的(命令行解释器)

所以 argv 里头的指针是 bash 的功劳啦,由于 子进程可以访问父进程的数据,那也就可以将我们输入的指令字符串切割后传入 argv 里让子进程访问到

结论

命令行参数是 C 语言支持让我们给 main() 函数传参的方式,支持我们写可变选项的程序,使同一个程序定制出不同的功能,就类似 Linux 里带选项的指令(百分之七十的指令都是 C 语言实现)

环境变量

环境变量(environment variables)一般是指在 OS 中用来指定 OS 运行环境的一些参数,如:我们在编写 C/C++ 代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关 环境变量 帮助编译器进行查找

一些现象

通过上面的实验,虽然已经可以为我们的程序带上选项,但 Linux 系统指令似乎并不用带上路径,类似 pwdls 等等,而我们的程序却要带上路径才能运行,成为进程,这是为什么呢?

其实 pwd 也有路径,不信的话,下面两句指令是一样的:

/usr/bin/pwd
pwd

指令可以不带路径是因为系统可以找到它呀 ^ ^

在 Linux 当中,存在一些 全局的设置,告诉命令行解释器,应该去哪些路径下去寻找可执行程序

而这个全局的设置是指: PATH ( Linux 环境变量的一个)

指定命令的搜索路径

查看环境变量

echo $PATH

结果就是:

/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/exercise/.local/bin:/home/exercise/bin

系统中有很多配置在我们登录 Linux 系统的时候,就已经被加载到了 bash 进程中(内存),其中就包括 PATH

bash 在执行命令的时候,需要先找到命令,因为是要提前加载的 ,所以 bash 内部维护了一批路径在环境变量里,而这些路径以 : 作为分隔符;
要执行哪个指令就会依次在这些路径下寻找,如果没找到,就会报 command not found 错误;如果找到了,就会加载并运行此程序

而上面 pwd 指令路径就在 /usr/bin/ 下,在 PATH 是存在的,所以不需要手动添加路径

注意:
上面查到的 PATH 默认是 内存级的环境变量,也就是说,一旦我们将 PATH 修改,而 系统配置文件不变,下一次登录时, PATH 值会恢复至原样

添加环境变量

添加内存级环境变量

如果我想自己写的程序也可以像指令一样直接被运行,就需要将此程序的路径添加至环境变量,使得 bash 可以找得到此程序,仔细阅读以下命令

[exercise@localhost envir_var]$ ./mytest
Usage: ./mytest - [a, b, c, d]
[exercise@localhost envir_var]$ ./mytest -a
It is function1
[exercise@localhost envir_var]$ ./mytest -b
It is function2
[exercise@localhost envir_var]$ pwd
/home/exercise/learn/linux-exer/process/envir_var
[exercise@localhost envir_var]$ PATH=$PATH:/home/exercise/learn/linux-exer/process/envir_var
[exercise@localhost envir_var]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/exercise/.local/bin:/home/exercise/bin:/home/exercise/learn/linux-exer/process/envir_var
[exercise@localhost envir_var]$ mytest
Usage: mytest - [a, b, c, d]
[exercise@localhost envir_var]$ mytest -a
It is function1
[exercise@localhost envir_var]$ mytest -b
It is function2
[exercise@localhost envir_var]$

发现此时的 mytest 可执行程序已经可以不带路径直接跑咯 ^ ^

也可以使用 which 指令查看验证哦:

which mytest

所以 添加内存级环境变量 为:

PATH=$PATH:你要添加的路径

永久有效

如果你重新打开终端或者重启系统之后,会发现上面添加的环境变量仅仅在当前 bash 有效,这是因为上面添加的是内存级的环境变量嘛,那如何实现永久有效呢?

那就要修改配置文件咯,对于云服务器来说,每次重新登录时,都会为我们创建一个新的 bash 进程,此 bash 进程会将配置文件数据拷贝一份到自己的内存中,其中 就包括 PATH

如何更改呢?在你的家目录下有一个隐藏文件叫做 .bash_profile ,使用 vim 打开就会发现如下内容:

# .bash_profile# Get the aliases and functions
if [ -f ~/.bashrc ]; then. ~/.bashrc
fi# User specific environment and startup programsPATH=$PATH:$HOME/.local/bin:$HOME/binexport PATH

很显然,我们看见了环境变量 PATH ,所以只需要需改此配置文件即可,在 PATH=$PATH:$HOME/.local/bin:$HOME/bin 的后面添加 :你要添加的路径 即可,我这里是

PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/exercise/learn/linux-exer/process/envir_var

那么步骤如下:

[exercise@localhost envir_var]$ ./mytest
Usage: ./mytest - [a, b, c, d]
[exercise@localhost envir_var]$ ./mytest -a
It is function1
[exercise@localhost envir_var]$ ./mytest -b
It is function2
[exercise@localhost envir_var]$ pwd
/home/exercise/learn/linux-exer/process/envir_var
[exercise@localhost envir_var]$ cd ~
[exercise@localhost ~]$ vim .bash_profile

然后重启一个终端即可

其他环境变量

在 Linux 里可不止 PATH 一种环境变量,如果你要查看系统中所有的环境变量,使用如下指令:

env

结果会非常多,琳琅满目,暂挑几个说:

HOME

指定用户的主工作目录(即用户登陆到 Linux 系统中时,默认的目录)

如果你是 普通用户,那么登录进入 Linux 系统后,所在位置一般都是 用户家目录

[exercise@localhost ~]$ pwd
/home/exercise

如果你是 超管 root ,那你的家目录就在 /root 下:

[root@localhost ~]# pwd
/root

为什么初次登录系统的目录是这个呢?当然是 系统的配置文件决定的 啦,它会为用户配置好系统家目录

[exercise@localhost envir_var]$ echo $HOME
/home/exercise

PWD

这是个有趣的环境变量:

[exercise@localhost envir_var]$ echo $PWD
/home/exercise/learn/linux-exer/process/envir_var
[exercise@localhost envir_var]$ cd ..
[exercise@localhost process]$ echo $PWD
/home/exercise/learn/linux-exer/process

会发现这就是我们当前的工作目录,这就是 pwd 指令为啥知道我们的工作目录呢?

这是因为系统有一个会变化的环境变量,会随着我们路径的变化,动态地将我们的路径记录在此环境变量里

SHELL

当前 Shell,它的值通常是 /bin/bash

机器启动时,会为用户创建一个命令行解释器 shell 提供服务,那 Linux 怎么知道要运行什么 shell 呢?

[exercise@localhost envir_var]$ echo $SHELL
/bin/bash

HISTSIZE

不知道大家是否会喜欢使用上键来翻找被执行过的历史指令,我甚至可以使用 ctrl + r 来搜索被执行过的历史指令,这些就说明我们使用过的历史指令是可以被系统记录下来的,但 Linux 系统总不能一直记录你所使用过的历史指令呀,所以 HISTSIZE 环境变量就表示 可以被记录的最新的指令条数

[exercise@localhost envir_var]$ echo $HISTSIZE
10000

也即是说系统会为我们维护最新的 10000 条指令,我们也可以使用 history 指令来查看被执行过的历史指令

自定义环境变量

定义

格式:

export name=val

例子:

export MY_ENV=HelloWorld

查看:

[exercise@localhost envir_var]$ env | grep MY_ENV
MY_ENV=HelloWorld
[exercise@localhost envir_var]$ echo $MY_ENV
HelloWorld

同样这也是 内存级的环境变量

取消

格式:

unset name 

例子:

unset MY_ENV

本地变量

就是不带 export 定义一个变量,观察以下操作:

[exercise@localhost envir_var]$ MY_VAR=123456
[exercise@localhost envir_var]$ env | grep MY_VAR
[exercise@localhost envir_var]$ echo $MY_VAR
123456
[exercise@localhost envir_var]$

会发现在 环境变量 里查不到 MY_VAR ,但可以 echo 出来,这就是 本地变量

整体理解环境变量

系统会把与登录相关的,与用户相关的,与路径相关的,与程序相关的等等,所有这些周边的,在系统中设置好的全局的变量就叫做环境变量

查看 所有环境变量 就是:

env

查看单个环境变量 XXX 就是:

echo $XXX

环境变量的组织方式

bash 内部会维护一张 环境变量表,本质就是个 字符指针数组,其内元素指向一个以 '\0' 结尾的字符串,最后一个元素指向 NULL
在这里插入图片描述

Linux 代码获取环境变量

方式一
#include <stdio.h>
#include <unistd.h>int main()
{// 其他头文件里的全局变量 environ(指针数组),需要 extern 声明extern char** environ;for (int i = 0; environ[i]; ++i)printf("env[%d] -> %s\n", i, environ[i]);return 0;
}

编译运行后观察结果,和 env 指令结果本质上是一样的,只是格式不一样

环境变量默认是可以被子进程拿到的,而环境变量默认是在 bash 内部,上面的程序运行为进程后会从 父进程 bash 里看到全局的环境变量并读取

bash 进程启动的时候,默认会给我们子进程形成两张表:

  • 命令行参数表 argv[] (从用户输入的命令行来)
  • 环境变量表 env[] (从 OS 配置文件来)

bash 会通过各种方式交给子进程,而把环境变量给子进程的一种方式就是此 二级指针

extern char** environ;

environ 没有包含在任何头文件中,所以在使用时 要用 extern 声明
其最后的末尾元素是 NULL 指针,而前面的元素内容也已被上面的代码所打印出来

方式二

这种方式和命令行参数很像,就是 main() 函数接收参数啦:

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

也就可以像下面这样获取:

#include <stdio.h>
#include <unistd.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;
}
方式三

子进程也可以通过 getenv() 函数获取指定环境变量:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char* argv[], char* env[])
{char* path = getenv("PATH");if (path == NULL) return 1;else printf("PATH = %s\n", path);return 0;
}

理解

环境变量具有系统级的全局属性,因为环境变量本身会被子进程继承下去

如果你在命令行启动一个进程 A ,那它的父进程是 bash ,自然可以继承 bash 的环境变量;但如果进程A 也启动一个子进程,此时也可以继承 A 的环境变量,如此继承下去

但有个地方不对劲,就是利用 export 指令自定义环境变量:
export 是指令吧?执行它不是要创建子进程吗?如果创建子进程,那子进程修改环境变量对于 bash 来说是不相干的呀,因为进程是具有独立性的

这是因为 export内建命令,Linux 大部分指令确实需要创建子进程来完成执行,但少部分指令却是由 bash 亲自执行的,再例如 echo 指令,这就是内建命令,暂且可以将其理解为一个函数或者是类的调用即可

也就是说系统对 内建命令 的执行是不需要 PATH 指路的,毕竟都不需要开启新的子进程,不信咱就可以把 PATH 设为空串试一下,试完重新登录即可

测试本地变量和环境变量

我们上面提到过 本地变量,那 本地变量 到底可以用来干啥呢?

看下面的一串指令:

[exercise@localhost envir_var]$ env | grep HELLO
[exercise@localhost envir_var]$ echo $HELLO[exercise@localhost envir_var]$ HELLO=123436
[exercise@localhost envir_var]$ env | grep HELLO
[exercise@localhost envir_var]$ echo $HELLO
123436
[exercise@localhost envir_var]$ export HELLO
[exercise@localhost envir_var]$ env | grep HELLO
HELLO=123436
[exercise@localhost envir_var]$ echo $HELLO
123436
[exercise@localhost envir_var]$

本地变量 还没有被 export 时,env 是查不到的,但 export 后却可以

而这 本地变量 是只在本 bash 内部有效,无法被子进程继承下去,导成 环境变量 才能被继承

这也可以解释 echo 为什么可以打印出 本地变量,这是因为 echo内建命令,由 bash 亲自执行,都不需要继承,获取自己内部的 本地变量 不是易如反掌吗?
而子进程是无法继承 bash 内部的 本地变量,所以 echo 也绝对不是以 bash 创建子进程的方式完成,而是由 bash 亲自执行才可,相互印证

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/51242.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器人学】7-2.六自由度机器人自干涉检测-计算圆柱体的上下圆心坐标【附MATLAB代码】

目录 前言 机械臂几何参数 机器等效圆柱体坐标确定 MATLAB代码 前言 上一章介绍了机器人自干涉检测的总体算法&#xff0c;提出了算法的三个核心&#xff1a; 一 根据机械臂的几何数据以及DH参数&#xff0c;确定机械臂等效的圆柱体的上下圆心坐标。 二 将一个圆柱体旋转到…

vue.js - 看板娘 Live2d

文中的资源文件在这里&#xff1a;我的资源中&#xff0c;打好包了已经&#xff0c;地址&#xff1a;live2d资源 1、在项目的 src/assets 文件夹中&#xff0c;添加 live2d 的资源文件 2、在 src/components 文件中&#xff0c;编写 live2d的index.vue组件 3、在 App.vue 中…

【重点】人工智能大语言模型技术发展研究报告2024|附下载

人工智能作为引领新一轮科技产业革命的战略性技术和新质生产力重要驱动力&#xff0c;正在引发经济、社会、文化等领域的变革和重塑。 2023 年以来&#xff0c;以ChatGPT、GPT-4 为代表的大模型技术的出台&#xff0c;因其强大的内容生成及多轮对话能力&#xff0c;引发全球新…

MYSQL————数据库的约束

1.约束类型 1.not null&#xff1a;指示某列不能存储null值 2.unique&#xff1a;保证某列的每行必须有唯一值 3.default&#xff1a;规定没有给列赋值时的默认值 4.primary key&#xff1a;not null和unique的结合。确保某列&#xff08;或两个或多个列的结合&#xff09;有唯…

聊聊最近很火的后端即服务

最近&#xff0c;你可能经常听到“后端即服务”&#xff08;Backend as a Service, BaaS&#xff09;这个词。不论是在技术论坛上&#xff0c;还是在开发者社区&#xff0c;BaaS都成了大家讨论的热点。究竟是什么让这个概念如此火爆&#xff1f;今天我们就来聊聊这个话题&#…

TCP粘包和抓包

在 TCP 套接字中&#xff0c;发送和接收缓冲区用于暂存数据&#xff0c;以确保数据的可靠传输。具体来说&#xff0c;TCP 的 socket 收发缓冲区的主要特点和概念如下&#xff1a; 1. 发送缓冲区&#xff08;Send Buffer&#xff09; 定义: 发送缓冲区用于存储待发送的数据。应…

大模型从入门到精通——词向量及知识库介绍

词向量及知识库介绍 1.词向量 1.1 什么是词向量 词向量是一种将单词表示为实数向量的方式。每个单词通过一个高维向量来表示&#xff0c;向量的每一维都是一个实数&#xff0c;这些向量通常位于一个高维空间中。词向量的目标是将语义相似的单词映射到相邻的向量空间中&#…

自定义@ResponseBody以及SpringMVC总结

文章目录 1.需求分析2.目录3.自定义ResponseBody注解4.MonsterController.java5.Monster.java 实现序列化接口6.引入jackson7.Adapter.java 如果有ResponseBody注解就返回json8.测试9.SpringMVC执行流程 1.需求分析 2.目录 3.自定义ResponseBody注解 package com.sunxiansheng…

24暑假算法刷题 | Day39 | 动态规划 VII | LeetCode 198. 打家劫舍,213. 打家劫舍 II,337. 打家劫舍 III

目录 198. 打家劫舍题目描述题解 213. 打家劫舍 II题目描述题解 337. 打家劫舍 III题目描述题解 打家劫舍的一天 &#x1f608; 198. 打家劫舍 点此跳转题目链接 题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷…

(贪心) LeetCode 135. 分发糖果

原题链接 一. 题目描述 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。 相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩子分发糖果&#xf…

OpenCV与AI深度学习 | 基于改进YOLOv8的景区行人检测算法

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;基于改进YOLOv8的景区行人检测算法 作者&#xff1a;贵向泉&#xff0c;刘世清&#xff0c;李立等 来源&#xff1a;《计算机工程》期刊 编…

docker应用

打包传输 1.将镜像打包 #查看帮助文件 docker --help #找到save&#xff0c;可以将镜像保存为一个tar包 docker save --help #查看save使用方式 #查看现有的镜像 docker images # docker save --output centos.tar centos:latest ls ...centos.tar... 可以将tar发送给其他用户…

class_4:条件语句和逻辑运算符

mood_index int(input("对象今天的心情怎么样&#xff01;"))if mood_index > 80:print("今天可以好好happy一下了")print("O(∩_∩)O哈哈~") else:print("今天还是乖乖的吧&#xff01;否则小命不保") #BMI 体重 /&#xff08;身…

css实现闪烁渐变背景,@property自定义属性

自 2024 年 7 月起&#xff0c;此功能适用于最新的设备和浏览器版本。此功能可能无法在较旧的设备或浏览器中使用。 property 是 CSS 中一个相对较新的功能&#xff0c;主要用于定义自定义属性&#xff08;即 CSS 变量&#xff09;的类型、继承性以及初始值。它允许开发者更好地…

Linux --- 文件系统

1. 文件系统的概念 Linux 文件系统是一种用于管理、存储和组织数据的层次结构&#xff0c;用于在 Linux 操作系统中管理磁盘上的数据存储。它定义了如何在存储介质&#xff08;如硬盘、固态硬盘或 USB 闪存&#xff09;上组织文件和目录&#xff0c;以及如何读取、写入和操作这…

java整合DL645-2007与Dl645-1997

注意事项: 前导字节-一般在传输帧信息前,都要有0~4个FE不等,所以这里要注意,对于主站来说,直接发送4个FE作为前导字节即可。而从站回复,就不一定了,根据厂家不同而不同,有些没有FE的,也有4个FE的,所以对于接受程序,一定要慎重传输次序-所有的数据项都是先传低字节,…

鸿蒙HarmonyOS实战:IPC与RPC设备内进程通信

基本 IPC&#xff08;Inter-Process Communication&#xff09;与RPC&#xff08;Remote Procedure Call&#xff09;用于实现跨进程通信&#xff0c;不同的是前者使用Binder驱动&#xff0c;用于设备内的跨进程通信&#xff0c;后者使用软总线驱动&#xff0c;用于跨设备跨进…

Latex 插入图片或表格导致页面空白过多

如图所示&#xff1a; Latex 插入图片或表格导致页面空白过多 我们可以采用这个方式来减少空白。 \documentclass{article} \usepackage{graphicx} % 包含图形支持 \usepackage{caption} % 提供更多对caption的控制% 设置标题上方和下方的间距 \setlength{\abovecaptionskip}{…

学习记录:js算法(十二):柱状图中最大的矩形

文章目录 柱状图中最大的矩形我的思路网上思路 总结 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1:上图 输入&#xff1a;…

mac 安装Arthas

mac安装有两种方式 1.第一步安装Arthas 第一种&#xff1a; curl -L https://arthas.aliyun.com/install.sh | sh 第二种jar包形式 curl -O https://arthas.aliyun.com/arthas-boot.jar个人比较推荐第一种因为运行测试成功了 第一种安装后可能会出现一些命令不符合 需…