目录
一、命令行参数:
我们常写的main函数是可以带参数的
int main(int argc, int argv[],int )
{
//...
return 0;
};
当我们在命令行输入带有main函数的程序时,
可以在程序的后面输入一些值
如图:
makefile文件:
myprocess:myprocess.c
2 gcc -o myprocess myprocess.c -std=c99
3
4 .PHNOY:clean
5 clean:
6 rm -f myprocess
~
c文件:
#include<stdio.h>
int main(int argc,char* argv[])
{
for(int i = 0; i < argc; ++i)
{
printf("i:%d,argv[i]:%c\n",i,argv[i]);
}
return 0;
}
当你输入n个值,argc的大小就是n
对应的,就会开辟一个大小为n的argv数组
argv数组的最后一个位置是NULL
第一个位置argv[0]一定是程序名
那么这个有什么用处呢?
其实我们输入的命令行,本质是一行字符串:
这一行字符串的意义: 程序的路径 + 名称 和 该进程匹配的选项
例如:
ls -l
ls -a
ls -d
ls -dla
….
ls本质是一个程序,后面的-x代表这个程序的不同的功能
你在命令行输入ls
本质上和你自己执行一个自己写的 ./xxx.c 可执行程序没有任何区别
因此,为什么有命令行参数:
命令行参数的本质是交给我们程序的不同选项,用来定制不同的程序功能,程序命令中会携带很多选项
父进程的数据,默认能被子进程看到并访问
且命令行中启动的程序,都会变成进程,其实都是bash的子进程
因此,我们平常在命令行中输入的命令,就是默认输入给bash父进程的
而bash就叫做命令行解释器
因此,bash就会把输入的字符串解释成对应的信息表
而子进程是可以看到父进程的信息的
因此,父进程就可以把对应的参数,初始化为argc,和argv[],再传给对应的子进程执行
二、环境变量PATH
1、理解什么是环境变量
可是,为什么我们在运行自己的程序时,必须加上./
执行ls pwd等程序却不需要呢?
而执行程序,首先要找到命令的所在位置,然后加载到内存中,再运行
所以,我们可以这样理解:
ls等命令不需要路径,是不是因为bash已经知道了这个程序的路径呢?
而且这个路径以某种形式默认着
而我们自己写的程序,因为没有这种默认,所以bash不认识,所以必须要指明路径
是不是这个原因呢?
是的,没错,就是如此
而这个默认的形式,就是环境变量,PATH
在Linux中,存在一些全局的设置,这些设置告诉命令行解释器,应该去哪些路径寻找可执行程序
这样,就不需要专门的再加上一个./路径
PATH是一个一系列路径的组合:
在执行一个程序时,如果这个命令在PATH的默认路径上逐个搜寻,如果找到了
就直接加载到内存并执行
如果没有找到,就提示找不到命令
这也就是为什么,当你输入一个字符串命令的时候
本质上其实是输入一个程序
这个字符串要被bash命令行解释器解释,这也就是为什么bash叫做命令行解释器
解释的过程,其实就是在环境变量设置的默认路径中,寻找对应程序的过程
如果找不到对应的程序
这个时候,命令行就会提示如下:
找不到命令行,这就是原因!
查看环境变量:
echo $PATH
(我这里用的是root用户,我们在使用自己的操作系统时,尽量不要使用root用户,因为权限太高,容易出事情)
那么,如果,我的程序也要像系统命令一样,不需要./就可以直接运行
怎么办?
很简单,比较简单粗暴的做法就是,直接cp我们的程序到/usr/bin/路径下
cp XXX /usr/bin/
这样,就可以像系统命令一样直接运行了
例如:当我把我的可执行文件直接拷贝到/usr/bin环境变量路径下,我就可以直接像执行命令一样,直接运行我自己写的文件。
但是强烈不建议这样做
因为会污染系统的指令集
但是事实上,这种环境变量只是一个内存级别的
什么意思?
当系统退出后,操作系统数据和代码退出内存,那么你的设置也就随之消失了
这也就说明,最开始的环境变量并不是保存在内存中,而是存在操作系统的配置文件中
每一加载Linux操作系统,都会读取加载操作系统的配置文件的内容
所以,你在修改PATH的时候,修改的只是内存中的运行备份
而没有修改操作系统的配置文件的内容
那么,配置文件在哪里?
在家目录下的:
bash_profile
bashrc
/etc/bashrc
那么,到底怎么加呢?
千万不敢这样加:
PATH = 某某某路径
这会导致,你直接篡改了整个环境变量,把原来系统的默认路径都直接修改了
这样,你原来的系统命令都不能用了
应该这样加:
PATH = $PATH:/某某路径
因此,PATH是Linux下默认查找程序命令和路径,也是which查找命令指令的默认路径
2、常见环境变量和操作
查看所有环境变量:
env
查看单个环境变量:
echo $环境变量名
导进自定义环境变量:(如果不加export,叫做本地变量)
export name=value (可以是数字、字符等)
删除环境变量:
unset XXX
示例:
export mypath=1111#添加
env#全局查找
echo $mypath#单独查找
unset mypath #删除
env#全局查找
常见的环境变量:
HOME:家目录
PWD:当前路径,会动态跟进修改
HISTSIZE:历史命令记录(Linux默认1000条,我的显示是10000条)
SHELL:外壳程序
3、整体理解环境变量,系统,程序
bash进程启动的时候,默认会给子进程形成两张表:
argv[]命令行参数表:有用户输入命令行形成
env[]环境变量表:由操作系统的配置文件读取来形成
其中,bash通过某种方式将两张表交给子进程(其实是通过execvpe函数,在进程替换部分有)
所以,本质上,echo $PATH命令的执行
其实就是在env[]环境变量表(二级指针数组)进行遍历查找并打印出来的过程
再继续理解,其实export环境变量,其实就是再env[]环境变量表中添加一个字符串而已
其实,mian函数最多可以有三个参数:
int argc, char* argv[], char* env[]
环境变量具有系统级别的全局属性,因为环境变量本身可以被子进程继承
为什么被子进程继承就有全局属性呢?
因为bash是所有进程的父进程
4、如何获取环境变量(c语言)
(1)getenv() 函数:
函数原型:
char *getenv(const char *name);
功能:根据给定的环境变量名称 name,返回对应的环境变量值(字符串形式)。如果该环境变量不存在,则返回 NULL。
示例用法:(variable意为变量)
#include <stdio.h>
#include <stdlib.h> // for getenv()
int main() {
char *env_value = getenv("PATH");
if (env_value != NULL) {
printf("PATH environment variable: %s\n", env_value);
} else {
printf("PATH environment variable not found.\n");
}
return 0;
}
(2)使用 extern char **environ
功能:environ 是一个全局变量,它指向当前进程的环境变量数组。可以遍历这个数组来获取所有的环境变量及其值。
示例用法:
#include <stdio.h>
extern char **environ;
int main() {
char **env = environ;
while (*env != NULL) {
printf("%s\n", *env);
env++;
}
return 0;
}
注意:使用 environ 时,需要包含 <stdio.h> 头文件,但不需要额外的 <stdlib.h>。
5、内建命令
Linux内建命令(built-in commands)指的是直接由shell(如bash)内部实现并提供的命令,而不是通过调用外部可执行文件来执行。这些命令被编译进shell的可执行文件中,因此在调用它们时不需要创建新的进程,执行速度相比外部命令更快,并且对shell的控制能力更强。
特点和用法:
-
性能优势:由于内建命令不需要调用外部程序,因此执行速度通常比外部命令更快,特别是在频繁调用时能显著减少系统资源的消耗。
-
对shell的影响:内建命令可以更深入地影响和操作shell的状态和行为,例如改变shell的环境变量、控制shell的作业和进程、修改shell的行为等。
-
通常的内建命令:具体的内建命令会因不同的shell而有所差异
以下是bash shell中常见的内建命令示例:
内建命令 | 功能 |
---|---|
cd | 切换当前工作目录 |
echo | 打印文本或变量到标准输出 |
alias | 创建命令别名 |
export | 设置环境变量 |
unset | 删除环境变量或shell变量 |
exit | 退出当前shell |
jobs | 显示当前作业(jobs)列表 |
fg | 将后台作业切换到前台 |
bg | 将作业置于后台运行 |
source 或 . | 执行shell脚本并保持在当前shell环境中 |
export、echo等为内建命令
也就是说,这些命令是bash内部的一个函数
执行这些程序时,不需要创建子进程
而是bash直接调用内部的函数
因此,命令分为两种:一个是普通命令,一个是内建命令
80%的命令是普通命令,普通命令需要创建子进程
本地变量(即未用export命令添加的环境变量成为本地变量)只在本bash内部有效,无法被子进程继承下去,需要export导入环境变量,即添加到环境变量表中,此时才能获取