一、命令行参数
1.1参数介绍
在写C语言程序时,main函数是否可以带参数呢?------ 是可以的
- int argc: 命令行参数的个数
- char *argv[ ]: 字符指针数组(指向各个命令行参数的字符指针所构成的数组)
我们写一段代码来打印一下看这些参数存着什么信息:
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{for (int i = 0; i < argc; i++) {printf("argv[%d]: %s\n", i, argv[i]);}return 0;
}
运行结果:
直接运行数组中只保存了一个元素,是可执行程序的名称
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess
argv[0]->./myprocess
在后面加点选项再运行一下:
可见数组中第一个元素始终是程序的名称,数组后依次保存着选项信息
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -a
argv[0]->./myprocess
argv[1]->-a
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -a -b
argv[0]->./myprocess
argv[1]->-a
argv[2]->-b
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -a -b -c
argv[0]->./myprocess
argv[1]->-a
argv[2]->-b
argv[3]->-c
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -a -b -c -d
argv[0]->./myprocess
argv[1]->-a
argv[2]->-b
argv[3]->-c
argv[4]->-d
结论:
我们在命令行数组的字符串,会被操作系统分割开,存储于变长字符指针数组argv[ ]中
1.2 命令行参数的意义
- 命令行参数的本质是交由程序不同的选择,用来定制不同的程序功能,使我们在一个程序中,根据参数选项的不同而执行不同的功能
- 在Linux中,相同的指令搭配不同的选项实现不同的功能,就是这个原理:ls -a ls -l
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>int main(int argc,char* argv[]){if(argc!=2){printf("请通过选项来选择功能:-a -b -c\n");return 1;}if(strcmp(argv[1],"-a")==0){printf("功能1\n");}else if(strcmp(argv[1],"-b")==0){printf("功能2\n");}else if(strcmp(argv[1],"-c")==0) {printf("功能3\n");}else{printf("command not found\n");}return 0;}
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess
请通过选项来选择功能:-a -b -c
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -a
功能1
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -b
功能2
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -c
功能3
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./myprocess -d
command not found
1.3 命令行参数传递
- 命令行中启动的程序都会变成进程,并且都是bash的子进程
- 命令行输入的字符串默认是给父进程bash输入的
验证:
当我们运行如下代码:
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>int main(int argc,char* argv[]){printf("I am paraent pid:%d ppid:%d\n ",getpid(),getppid()); return 0;}
多次运行发现该进程的父进程都是27017 (bash)
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./a.out I am paraent pid:27285 ppid:27017 [zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ ./a.out I am paraent pid:27309 ppid:27017
二、环境变量
2.1 引入
通过对命令行参数的学习,我们了解了 指令+选项 的原理是什么,而指令也是可执行程序,相比于我们自己写的程序,指令只需要指令名称+选项就可以直接运行,但是我们自己写的程序想要运行就得加 ./,
原因是什么呢?
-----Linux存在一些全局的设置,告诉命令行解释器应当去哪些路径下寻找可执行程序,系统的很多配置在登陆Linux系统时,就已经加载到bash进程中了,bash在执行命令的时候需要先找到命令,这些路径就存储与环境变量(PATH)中
2.2 环境变量:PATH
PATH : 指定命令的搜索路径
//可以通过 echo $PATH 来查看其内容
- 这一串路径以 :分割
- 像 ls pwd 等指令的路径就存储于这写特定路径中,所以直接可以用指令名称运行
- 用户自己编写的程序默认并没有保存在环境变量中,直接使用程序名字系统查找不到指令的具体路径,所以需要加 ./ 才能运行
问题:怎样才能使用户编写的程序可以直接用程序名字运行呢?
---------只需要将程序的路径加载到PATH环境变量中就可以了
例如:可执行程序名字叫:mycode 存储路径:/home/zyq/file
$ PATH=$PATH:/home/ll/xxx/10# 注意:必须加上$符号,否则会把PATH中所有内容覆盖掉
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ PATH=$PATH:/home/zyq/file
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/zyq/.local/bin:/home/zyq/bin:/home/zyq/file
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ mycode
hello world
但是这样有一个问题,当我们重启系统时,PATH环境变量中的内容又会恢复原样
这是因为我们查询到的环境变量都是内存级的,最开始的环境变量并不是存储于内存中,而是存储于配置文件中的,当系统登录时,会将配置文件中的信息导入到内存中,顾重新启动会导致内容又会恢复原样,所以想要永久让我们使用程序名字直接运行程序需要将路径保存到配置文件中去(不建议随便更改配置文件中数据)
配置文件存储于家目录中,比如 .bash_profile 文件,我们可以直接在后面追加程序的路径即可
2.3 HOME环境变量
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
[zyq@iZf8z3j2ckkap6ybtz8qseZ ~]$ echo $HOME
/home/zyq
2.4 SHELL环境变量
SHELL : 当前Shell,它的值通常是/bin/bash
[zyq@iZf8z3j2ckkap6ybtz8qseZ ~]$ echo $SHELL
/bin/bash
2.5 与环境变量相关的命令
1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量
2.6 如何获取环境变量
-
通过第三方变量environ获取
extern char **environ;//第三方变量for(int i=0;environ[i];i++){//environ[i]中保存着环境变量printf("env[i]:%s\n",environ[i]);}
- 通过命令行第三个参数
main函数还可以传第三个参数,储存系统的环境变量信息,由系统提供
#include<stdio.h>#include<unistd.h>int main(int argc,char* argv[],char* env[]){int i=0;for(i=0;env[i];i++)printf("env[%d]:%s\n",i,env[i]); return 0;}
- 通过C库函数 getenv()获得
char *getenv(const char *name); // 通过名字获取环境变量
#include<stdio.h>#include<unistd.h>int main(){char* ret=getenv("PATH");printf("%s",ret); return 0;}
理解:
环境变量信息在系统启动时就从配置文件中被加载到了bash进程中,而所有命令行执行的程序都是bash的子进程,通过子进程也可以获取到环境变量,说明父进程的环境变量信息可以被子进程继承获得,环境变量具有系统全局性
2.7 环境变量与本地变量
- 环境变量:可以被子进程继承获得,具有系统全局性
- 本地变量:只能在当前进程被访问,不能被子进程继承
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ HELLO=123456 //创建名为HELLO的本地变量
查看本地变量:
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ echo $HELLO //查看方法与环境变量一致
123456
ps:虽然本地变量可以被查找出来,但是其并没有与环境变量存在一个地方,通过env查找所有环境变量里面依旧找不到HELLO
可以通过指令来将本地变量导为环境变量:
[zyq@iZf8z3j2ckkap6ybtz8qseZ file]$ export HELLO=12345
问题来了:
指令export的本质是可执行程序,那他执行一定会创建子进程,子进程可以访问父进程的资源是因为继承,而子进程做一些环境修改父进程是看不到的,那为什么bash可以查找到HELLO的信息呢?
这是因为echo export等指令是内建命令,内建命令是有bash直接执行的,不需要创建子进程,而Linux 80%的指令都是创建子进程执行的