Linux知识从无到有(持续更新)

目录


一、什么是Linux?什么是操作系统?

在初学Linux的时候我们都知道Linux是一个操作系统,那么操作系统是什么呢?
首先让我们再回顾一下冯诺依曼体系结构:

1、冯诺依曼体系五大部件结构
在这里插入图片描述
出于对效率提升的需求,如果外设和内存直接联系的话,当外设在接收文件时cpu就一直处于等待的状态,这大大降低了计算机处理数据的效率,所以外设和cpu不可以直接联系,而是通过中间的内存对双方的数据进行储存,进而达到数据的传输。
用聊天时的数据流向来看整个过程:
在这里插入图片描述
2、那么冯诺依曼结构这和操作系统又有什么关系呢?
首先让我们弄清楚操作系统是干什么的,操作系统是对计算机软硬件进行管理的软件,而冯诺依曼结构奠定的是是现代计算机的硬件结构。
所以操作系统就是对冯诺依曼中提到的硬件和计算机中的软件进行管理的软件。
没错,归根结底操作系统也是一款软件。
想想你是怎么使用一款软件的,这款软件和那些软件也是一样的,不过是一款管理软件的软件而已。
操作系统的结构:
在这里插入图片描述
操作系统具体怎么操作软硬件我们后面再细讲。
3、了解了什么是操作系统,那我们再来说说windox操作系统和Linux操作系统又有什么不同为什么我们学习的不是windox操作系统而是linux操作系统呢?
让我们看看两者的对比:
在这里插入图片描述
注意:
在这里插入图片描述

二、为啥要学习linux?什么是linux命令?

为啥要学习linux?
linux几乎是现在互联网公司的后台程序开发系统,windows操作系统更多的对应的是pc端的使用。为啥要学习linux可以说是不言而喻了。
什么是linux命令?
在linux中所学习的所有命令自己本身也是程序,对应到Windows操作系统当中相当于一个个.exe的程序,各种命令行参数相当于程序里不同的函数,这样一来对命令的理解是不是就贴切多了,只是在另一个操作系统中使用原来已有的程序而已。
在linux操作系统中命令执行之后的现象也是有很多种的,一些命令在运行完成之后就结束了,而一些命令执行之后回陷入类似等待的状态,此时使用ctrl + c结束进程即可。

三、linux的基本指令

1、ls命令

ls:罗列文件夹下的文件以及文件夹
pwd 查看当前文件夹或者文件的路径
ls -a:显示隐藏文件增加的,-a是命令行参数
ls -l 显示文件或文件夹的详细信息(简写ll)
在这里插入图片描述
ls -lrt 安时间对文件夹和文件进行排序
ls / 罗列根目录之下所有的文件夹
在这里插入图片描述

2、cd命令

cd :切换目录进入文件夹
cd /:cd到根目录下
cd ~: cd到当前用户的家目录下
cd -:回到上一个文件夹上
cd …:回到上级目录
cd /[tab]:命令补全,补全文件的路径

3、文件夹命令

mkdir[文件夹名称] :创建文件夹
touch[文件名称]:创建文件

4、删除命令

rm:删除文件
rm -r:删除文件夹
rm -rf /:从根目录之下开始删除
rm -i :对删除内容进行一步一步的提示删除

5、拷贝命令

cp [待拷贝 的文件] 拷贝到的[path]:拷贝文件
cp -r [待拷贝的文件夹] 拷贝到的[path]:拷贝文件夹
cp [拷贝文件]拷贝到的 [path]/文件重命名的[名称]:拷贝文件之后进行重命名
cat 查看文件内容

6、移动文件命令

mv [文件夹/文件路径] 移动到.(当前目录下)/~(家目录下)/想移动到的路径:移动文件/文件夹
mv[原名称]替换成[新的名称]:文件/文件夹的重命名

7、压缩文件/文件夹的命令

zip压缩
zip [压缩文件之后的名称].zip[待压缩的文件]加:压缩文件
zip -r [压缩文件夹之后的名称].zip[待压缩的文件夹]加 :压缩文件夹(-r递归压缩文件夹下的文件)
unzip [待解压的文件和文件夹名称] :解压缩
tar压缩(包含两种压缩)
gzip压缩:
tar -zcvf [压缩后的名称].tar.gz[待压缩的文件或者文件夹]:压缩文件
tar -zxcf [待解压缩的文件].tar.gz:解压文件
bzip2压缩:
tar -jcvf [压缩完成文件的名称].tar.bz2[待压缩的文件]:压缩文件
tar -jxcf [解压缩的文件].tar.bz2:解压缩文件

8、查看大文件内容的命令

more [文件名称] :查看文件内容,b向前翻页,f向后翻页
less[文件内容]:查看文件内容,b向前翻页,f向后翻页,两个命令采用的都是预加载的方式对大文件进行显示
head[文件名称]:查看文件头部内容,默认十行内容
head -n[num]加[文件名称]:查看文件头部的num行的内容
tail [文件名称]:查看文件尾部的内容
tail -f [ filename]:检测文件是否有变化,若有变化直接将变化显示到当前界面中
ctrl+c:1、中断当前的命令输入,2、结束正在执行的前台进程

9、操作文件的命令

cat[文件名]:查看文件内容
echo[字符串]>[文件名称]:往文件中写入内容
find[path]-name[文件名称]:查找文件所在的路径
grep[要查找的字符串]-R[path]:1、查找文件中的字符串,2、配合管道符号过滤其他命令的输出结果:
在这里插入图片描述
date :查看当前时间
在这里插入图片描述

tree:查看目录结构,显示文件夹的层次结构
在这里插入图片描述
histroy:查看历史执行过的命令
快捷执行之前执行的命令:
1、![之前执行过的命令的头部内容]
2、![命令]:快捷执行之前执行过的命令
3、使用键盘向上键寻找之前使用过的命令
//table快速补全命令行
在这里插入图片描述

10、切换用户的命令

su -root:从普通用户切换到root用户
exit: 回到普通用户
su [用户名称]:普通用户间相互切换

11、man查看函数和命令介绍

man手册的安装命令(注意要在root用户下安装)

#安装man
yum install -y man
#安装man-page
yum install -y man-pages

main 1 [命令名称]:查看命令介绍
main 2 [系统函数名]:查看系统函数的介绍
main 3 [库函数的名称]:查看库函数的介绍

四、命令行解释器(shell)

1、解释命令行解释器

上文所列出的各种操作命令是如何具体实施完成操作的呢?
在这里插入图片描述
此处的/bin/bash就是命令行解释器,上述的所有命令都是提交到命令行解释器,再命令行解释器传递到操作系统内核。也就是说命令行解释器只是一个中间的接口。
在这里插入图片描述

五、权限

1、权限的种类

-r 可读权限
-w 可写权限
-x可执行权限

2、权限的对象:用户、用户组、其他用户

权限有三个操作对象,分别是当前用户(u),当前用户组(g)和其他用户(o),在一个操作系统下有着多个用户组,每个用户组下有着不同的用户,彼此互为其他用户,即单个用户(家目录)和它所在的用户组以及其他用户,就是权限的操作对象。
一个文件或者文件夹,针对当前文件/文件夹所属的用户,当前文件/文件夹所属的用户组,当前文件/文件夹对应其他用户三个对象就要设置三个权限。
在这里插入图片描述

3、更改权限

三个对象对应都有三个权限,分别是可读、可写、可执行,顺序不变对应填写r w x如果该对象没有某个权限就填写 -
针对当前所属用户:r w x
针对当前所属用户组:r w x
针对其他用户:r w x
更改命令权限:
1、chmod (用户标识符)+/- (权限) [文件名称]
原本的权限:
在这里插入图片描述
更改后的权限:
在这里插入图片描述
2、chmod (权限数字) [文件名称]
将权限对应位置看作二进制数字,若1为具有权限,0就没有权限
例如我们现在再将hello这个文件的用户权限改成可读可写:
在这里插入图片描述
得到权限数字664
在这里插入图片描述
这样就又更改权限为可读可写了。

六、编辑器和编译器工具(vim、gcc/g++)

1、编辑器vim的快捷键

1、移(在NOEMAL模式下光标的移动):
j:下,k:上,h:左,l:右,
w:切换到下一个词的词首,b:切到上一个词所在的词首,

2、删除
dd:剪切当前行的内容,p:粘贴剪切内容到光标所在的下一行,[num]dd:删除num行,
x/[num]x:删除光标所在位置的一/num个字符,X/[num]X:删除光标所在的前一/num个字符,

3、复制
yy/[num]yy:复制一/num行,p:将内容复制到光标所在的下一行,P:将内容粘贴到光标所在的上一行

4、替换
r:替换光标所在的字符,R:进入到替换模式可以替换多个字符。

5、撤销
u:撤销,ctrl+r:返撤销,

6、更改
c:删除光标后面的所有元素,并自动切到INSERT模式。
cw:删除光标所在的单词,并自动切到INSERT模式。

7、跳转
gg:跳转到文件的头部,G/shift+g:跳转到文件的尾部,[num]G:跳转到文件的任意一行,ctrl+o:跳转到上一次的位置, gg=G/shift+g:缩进模式,
I:光标回到当前行的行首,A:光标跳到行尾位置,
o:从光标的下一行开始插入,O:从光标的上一行开始插入。
多行注释:
ctrl+v:进入可视模式 j/k选中行,I+//:输入注释符,esc:执行命令
多行删除:
ctrl+v:进入可视模式 j/k选中行,x:执行命令,

2、命令行模式下的指令

分屏打开文件:
:vs[文件名称]
:ctrl+ww:在分屏中跳转
替换字符串:
:s/代替换的字符串/替换的字符串/g:单个替换
:s/代替换的字符串/替换的字符串/g:全部替换
:/[搜索的字符串]:查找某个字符串+n找下一个匹配的字符串

3、编译器(gcc/g++)

程序的四个编译过程:预处理、编译、汇编、链接,gcc编译器用来编译c语言,g++编译器编译c/c++ 。
查看源码:
在这里插入图片描述
1、预处理
命令:gcc -E [程序名称] -o [编译后文件的名称]
在这里插入图片描述
2、编译(对语法语义进行检测,并且生成汇编代码)
命令:gcc -S [程序名称] -o [编译后文件的名称]
在这里插入图片描述
3、汇编
命令:gcc -c [程序名称] -o [编译后文件的名称]
在这里插入图片描述
4、链接
将目标程序和库链接在一起生成目标程序
命令:gcc [程序名称] -o [编译后文件的名称]
在这里插入图片描述
绿色的就是可执行的文件
在这里插入图片描述

4、在debug版本下调试程序的两种方法

4.1什么是debug版本?

程序在我们编写时时debug版本,在这个版本之下对程序进行调试修改,修改完毕之后发布给客户的是不具备修改权限的release版本。

4.2debug版本怎么生成?

命令:gcc [程序名称] -o [编译后的文件名称] -g
在这里插入图片描述

4.3两种调试方法(调试可执行程序、调试coredump文件)

4.3.1调试可执行程序

命令:gdb [可执行文件名称]
1、查看源代码: l
在这里插入图片描述

2、打断点:b [行号]

3、删除断点:delete[断点序号]

4、查看断点信息:i b

5、disable [断点序号]:使断点失效

6、enable[断点序号]:使断点生效

7、r: 启动程序

8、s:逐语句执行

9、n:逐过程执行

10、c:继续执行

11、p [变量名]:打印变量信息

12、q:退出命令

4.3.2调试coredump文件

coredump文件是啥?
程序崩溃之后产生的内存镜像文件,文件里保存的是文件崩溃瞬间文件里的内容,它的存在让我们在程序崩溃之后还能对程序进行更改修正。
怎样产生coredump文件
1、更改core file size值为无限。
ulimit -a :查看所有镜像文件的大小
在这里插入图片描述
ulimit -c: 单独查看内存镜像文件的大小
2、ulimit -c unlimited
设置内存镜像文件大小为无限。
在这里插入图片描述
3、保证磁盘空间足够。
4、怎么调试coredump文件?
1、gdb[可执行程序]+[coredump文件]:打开gdb调试界面

2、bt:查看调用堆栈(堆栈从下往上看,最终因此程序奔溃的堆栈在顶层)
3、f [堆栈序号]:跳转到某个具体堆栈

4、通过make(自动化解释器)解释makefile(文件)进而生成可执行程序

在没有构造解释器之前,生成一个可执行文件需要一步步完成,而解释器就是对这些步骤的封装。
在这里插入图片描述
makefile文件如何生成?
1、make一个makefile文件,
2、makefile文件内容格式:
在这里插入图片描述3、make命令执行makefile文件
在这里插入图片描述
解释makefile的生成原则
1、make解释器在执行之前会对目标对象和依赖对象的时间进行比较,判断目标对象是否需要重新执行。
2、生命周期:第一个目标对象生成之后结束工作
3、若一次有多个可执行程序怎么在makefile文件中定义?
命令:all[目标文件名…]
在这里插入图片描述
makefile中的预定义变量(简化makefile的编写
$^:依赖对象 $@:目标对象
在这里插入图片描述
makefile中定义删除目标文件
命令:clean:rm[目标对象]
在这里插入图片描述
使用过程:
在这里插入图片描述
makefile文件中的自定义变量文件
怎么使用自定义变量?
在这里插入图片描述

七、进程

1、什么是进程?进程和程序之间的关系是什么?

程序是指源代码经过编译之后的静态可执行文件,
进程就是进行中的程序,即程序运行时的实例对象,是动态的,
我们也可以这么理解,静态的程序从内核分配到资源之后,开始运行变成了动态的进程。

1.1如何查看进程信息?

命令: ps aux
在这里插入图片描述

1.2如何查看具体某个进程信息?

通过管道查看,命令:ps aux | grep[./程序名称]在这里插入图片描述

2、进程在哪里被管理?进程的格式是怎么被描述的?

操作系统使用描述加组织的方式管理进程,并使用进程控制块(PCB)描述进程
ed:怎么打开多个终端?(在后续对运行中的进程进行观察时需要使用到)
1.ctrl+alt+t:打开一个终端。
2. ctrl+shift+t :在当前终端中新建终端
3.Alt+n:切换到第n个终端

2.1进程在操作系统中的描述格式(PCB):

2.1.1什么是进程标识符(PID)?如何查看PID?

是某个进程相关的唯一标识符,用来区别其他进程。
ps aux | grep [程序名称]

2.1.2进程状态

并行:多个进程在同一个时刻,拥有不同的CPU进行运算称之为并行,
并发:多个进程在同一时刻只能有一个进程拥有CPU进行运算称之为并发,
R:运行状态
S:可中断睡眠状态
D:不可中断睡眠状态
T:暂停状态(ctrl+z)使进程暂停,并不是退出运行,(fg)结束暂停
t:跟踪状态,在gdb调试的时候出现,
X:死亡状态
Z:僵尸状态

2.1.3什么是程序计数器?什么是上下文信息?

CPU是有限的,而进程是无限的,每个进程不一定操作结束才被切出,在操作过程中也存在着被切出的现象,程序计数器对进程在操作过程中被中断时的指令进行保存,上下文信息对指令需要的数据进行保存,以确保下次进程重新回到操作系统时依旧能够接着此前的指令进行,
在这里插入图片描述

2.1.5 内存指针

内存指针指向程序的地址空间。

2.1.6 记账信息

记录cpu使用时长,占用内存大小等信息,

2.1.7 IO信息

IO信息中保存着当前进程打开文件的信息,
/proc文件夹:以文件夹的形式保存着当前操作系统所维护的所有进程的信息(IO信息)
在这里插入图片描述

3、什么是父进程什么是子进程?

子进程的PCB完全拷贝来自父进程,内存指针指向同一个地址空间,所有的代码段也是完全一样的,
在这里插入图片描述

eg:父子进程具有相同的代码段执行的事件是一样的吗?

是不一样的,父子进程在执行了fork函数之后会有不同的返回值,不同的返回值执行的程序是不同的,即可以理解为划分父子进程不同的区分点。
-1:创建失败

0的返回值:创建成功(返回给父进程)
==0的返回值:创建成功(返回给子进程)
在这里插入图片描述
在这里插入图片描述

3.2如何创建子进程?

在父进程中使用fork函数创建子进程。
pid_t fork(void):创建子进程
在这里插入图片描述

3.1如何查看父子进程id号?

pid_t getpid(void):获取当前进程的pid号,谁调用获取谁。
pid_t getppid(void):获取当前父进程的pid号,谁调用获取谁的父进程pid号。
在这里插入图片描述 在这里插入图片描述

3.2.1如何区分子进程和父进程?

命令:ps -ef | grep [进程名称] :展示输出父进程和子进程的id号
在这里插入图片描述

4、什么是僵尸进程?僵尸进程是怎么产生的?

僵尸进程是指在一个进程结束之后,本该被操作系统释放的结构体没有被释放,依然存在,进而造成内存泄漏现象的进程
当子进程先于父进程退出时,子进程通过信号通知父进程前来回收资源,但是父进程没有回收子进程的资源,从而导致子进程的PCB得不到释放,变成了僵尸进程
在这里插入图片描述

4.1 如何结束僵尸进程?

在此之前我们会使用kill命令杀死进程:kill[pid] / kill -9 [pid] 但是该命令只对“活”进程有用,由于僵尸进程已经造成内存泄漏所以是不可以被该命令杀死的。一下几种结束僵尸进程的方法:
1、重启操作系统
2、kill僵尸进程的父进程
3、进程等待:父进程通过等待的方式,回收子进程的资源,获取子进程退出的信息。
函数:
pid_t wait(int*status);
成功返回进程pid 失败则返回-1

pid_ t waitpid(pid_t pid,int *status,int options):
成功返回子进程进程id,
在这里插入图片描述

5、什么是孤儿进程?

当父进程先于子进程退出时,由于父进程退出,资源无法被回收的子进程被1号进程“领养”回收资源,否则会变成僵尸进程,像这样的进程就叫做孤儿进程。
在这里插入图片描述

4、什么是环境变量?

环境变量是指指定操作系统运行环境的参数。环境变量指定参数,让bash能够在操作系统使用命令运行时,通过指定的参数找到能够使命令运行的文件。
当环境变量没有指定参数:
在这里插入图片描述
常用的ls ll 等命令都是环境变量指定的参数。
在这里插入图片描述

4.2 怎么查看环境变量?

1、echo $[环境变量名称]

2、env:以键值对的方式储存
在这里插入图片描述

4.3 常见的环境变量都有那些?

1、PATH:保存着所有可执行程序的搜索路径
当程序中使用例如ls,ll等命令时,bash会在PATH中包含的所有路径中逐个查找已保存可执行程序的文件,找到命令要求的文件夹对应执行动作。
在这里插入图片描述
2、SHELL:保存命令行解释器名称
在这里插入图片描述
3、HOME:保存当前用户的家目录
在这里插入图片描述

4.4 怎么设置环境变量?

4.4.1 设置临时生效的环境变量(只在当前的终端中生效):

export[环境变量名称]=$【环境变量名】:【新增加的路径】
在这里插入图片描述

4.4.2设置永久生效的环境变量(在新的终端中直接从文件夹中读取内容)

1、 ~/.bashrc
2、 ~/.bash_profile
vim ~/.bash_profile:进入文件夹
export:[环境变量文件名称] =$[环境变量文件名称]😕[文件路径]:添加环境变量
在这里插入图片描述
source ~/.bash_profile
将文件中修改的东西同步更新到磁盘内存中
在这里插入图片描述

4.4.3怎么在代码中获取环境变量?

1.将argc(命令行个数)和argv设为函数参数获取环境变量

函数: int main(int argc,char* argv[])
输出:
在这里插入图片描述
可执行程序也包含在环境变量中
在这里插入图片描述
设置命令行参数的作用:自定义代码实现分支逻辑
在这里插入图片描述

2、设置env参数获取环境变量

函数: int main(int argc,char* argv[],char* env[])
在这里插入图片描述
在这里插入图片描述

3、通过environ参数获取环境变量(配合extren关键字使用)

在这里插入图片描述

5、什么是进程的虚拟地址空间?进程是如何通过虚拟地址空间找到实际地址空间的?

操作系统中每个进程都有的虚拟地址,每个进程修改自己虚拟地址的值不会影响别的进程数据,这保证了进程的独立性
在程序中定义一个全局变量,在父子进程中分别输出变量的值和地址,变量的值相同,地址也相同,指向相同的空间因此值相同看似没有任何问题
在这里插入图片描述
但是,让我们在子进程中更改g_val的值看看:
在这里插入图片描述
再次输出时,变量的值不同,地址却还是一样的,这个地址便是虚拟地址。
在这里插入图片描述
进程的虚拟地址通过叫做页表的结构映射实际储存的物理地址。
在这里插入图片描述

5.1页表的分页式,分段式,段页式储存映射虚拟地址与物理地址

1、分页式:将虚拟地址分成一页一页的小块,块的大小是4096字节。
虚拟地址的组成:页号+页内偏移
页号:虚拟地址/块大小 (找到块号)
页内偏移:虚拟地址%块大小(加上业内偏移就能在块内找到具体的物理地址)
页号找到对应的块号,进入对应物理内存的块号里加上页内偏移找到对应的物理地址
在这里插入图片描述
2、分段式:
虚拟地址:段号+页内偏移
在这里插入图片描述

3、段页式:
虚拟地址:段号+页号+页内偏移
在这里插入图片描述

什么是进程优先级?

进程的优先级即cpu资源分配的先后顺序,在多任务待执行的操作系统环境下,配置进程优先权能够大大改善系统性能,

如何查看进程的优先级信息?如何修改优先级?

命令:top 查看进程优先级信息
在这里插入图片描述
更改NI值改变进程优先级
1、进入top窗口
2、按下r -> 输入进程号 -> 输入NI(-20至19)值
普通用户只能降低进程优先级,要更改提高进程优先级,需要切到root用户下

八、如何实现对进程进行控制?

1、如何实现进程创建?

通过fork()函数创建进程

让我们回忆一下父子进程之间的关系:

  • 我们通过拷贝父进程创建子进程,子进程的PCB以及大部分数据(数据段和代码段)都来源于父进程,
  • 两个进程是独立的,执行两个进程的先后顺序是抢占式执行,
  • 子进程自己的虚拟地址空间指向独立的物理空间,这保证了两者之间的独立性

fork函数创建失败的几种情况

  • 实际进程过多,创建失败
  • 实际使用用户人数过多,超过限制

2、如何实现进程终止?

进程终止的几个场景:

  • 从main函数的return返回,代码执行成功或失败,返回执行结果
  • 程序奔溃

2.1终止进程的方法

1、从main函数中return返回

2、使用exit函数

  • exit函数-库函数
    void exit(int status);
    退出时的参数status会被等待接口获取到
    在这里插入图片描述
    在这里插入图片描述
  • _exit函数-系统调用函数
    void _exit(int status);
    与exit函数实现的功能是一样的,退出时的参数status会被等待接口获取到

exit函数和_exit函数的不同点

  • exit函数是库函数,_exit函数是系统调用函数
  • exit函数会冲刷缓冲区,关闭流,_exit()函数不会刷新缓存区
    没有加\n(刷新缓存区)时exit函数的输出

    没有加\n(刷新缓存区)时_exit函数的输出
    在这里插入图片描述

2.2什么是缓冲区?\n和缓冲区有什么关系?

程序的运行结果在被操作系统输出之前,是暂存在缓冲区中的,缓冲区只有在内部内容全部满了才会自动输出,此时对其的刷新动作,即提示缓冲区将内部已有的内容进行输出。
在这里插入图片描述
系统调用函数越过了c库直接对缓冲区中的数据进行管理
在这里插入图片描述

2.3如何查看函数退出时返回的参数?

命令:echo $?
在这里插入图片描述

3、执行用户自定义的清理函数

回调函数:int atexit(void (*function)(void));
在这里插入图片描述

4、什么是进程等待?如何实现进程等待?

进程等待:防止子进程先于父进程退出产生僵尸进程,保证子进程在父进程之前退出,父进程对子进程进行等待回收子进程的资源,

4.1wait函数

出参函数:pid_t wait(int *status);
wait函数成功返回子进程id,失败返回-1
在进程正常情况查看进程退出码,在异常情况下查看coredump标志位和终止信号进行调试
在这里插入图片描述
如何获取进程退出码?
status>>8 & 0xff
如何获取终止信号?
status & 0x7f
如何获取coredump标志位?
status>>7 &0x1
子进程在退出时给父进程返回SIGCHILD信号给父进程提醒父进程对资源进行回收,但父进程对该信号是忽略的,此时设置wait函数即对SIGCHILD信号进行接收,通知父进程回收资源。
在这里插入图片描述

4.2什么是阻塞状态?怎么查看阻塞状态下进程在处理的事情?

调用了一个函数,该函数一直没有返回时,这个现象就称之为阻塞状态,此时可以通过pstack查看进程正在处理的事情。
命令:pstack[pid]查看进程调用堆栈的命令

4.3waitpid函数

函数:pid_t waitpid(pid_t pid, int *status, int options);
pid:
-1:等待任意子进程
大于0:等待特定的子进程,传递的值就是子进程的PID号
status:出参与wait函数一样
options:
0:阻塞等待方式
WNOHANG:非阻塞等待方式要搭配循环进行实现其非阻塞的等待,即在未等待到子进程的退出码时,设置别的数值进行输出
在这里插入图片描述

5、什么是进程替换?如何实现进程替换?

进程替换指将正在进行中的进程替换成另外一个程序,进程替换主要应用于守护进程,实现进程不间断的运行,但仅仅避免因为进程程序崩溃导致的进程运行中断,程序崩溃的错误还是需要后期更改修正。
在这里插入图片描述
实现进程替换的接口
exec函数簇
1、int execl(const char * path,const char *arg,…);
path:路径+待替换的可执行程序的名称
arg:给待替换的可执行程序传递的参数(可执行程序本身,…NULL)

2、int execlp(const char *file, const char *arg, …);
file:只需要传递待替换的可执行程序
(如果只传递名称要确保可执行程序已在环境变量中设置了,否则将文件路径一并设置好)
arg:给待替换的可执行程序传递的参数(可执行程序本身,…NULL)
带p的execlp函数会自动搜索环境变量PATH

3、int execle(const char path, const char arg, …, char * const envp[]);
path:带有路径的可执行程序
arg:给待替换的可执行程序传递的参数(可执行程序本身,…NULL)
envp[]:指针数组,本质是数组,数组的每个元素都是char
,其中的环境变量都是自己组织的最后一个元素放入NULL,在使用envp[]数组时也可以直接调用c库定义的数组environ,记得使用extrern char
* environ 申明
带有e的函数需要自己组织环境变量放到envp[]指针数组中以NULL结尾。
带有l的函数表示给待替换的可执行程序传递的命令行参数为可变参数列表

4、int execv(const char *path, char *const argv[]);
path:带有路径的可执行程序
argv[]:存放传递给可执行程序的命令的指针数组,以NULL结尾
带有v的函数表示给待替换的可执行程序传递的命令行参数为指针数组

5、int execvp(const char *file, char *const argv[]);
file:搜索环境变量
argv[]:存放传递给可执行程序的命令的指针数组,以NULL结尾

6、int execvpe(const char *file, char *const argv[],char const envp[])
file:搜索环境变量
argv[]:存放传递给可执行程序的命令的指针数组,以NULL结尾
envp[]:指针数组,本质是数组,数组的每个元素都是char
,其中的环境变量都是自己组织的

6、什么是minishell?

minishell就是精简版本的命令行解释器,作为进程替换的具体实现进行学习,其中包含父子进程进行循环,父进程进行进程等待,子进程进行进程程序替换成为命令程序

#include<stdio.h>                                                                            
  2 #include<unistd.h>
  3 #include<string.h>
  4 #include<sys/wait.h>
  5 #include<stdlib.h>
  6 int main()
  7 {
  8   while(1)
  9   {
 10   printf("minishell@localhost $  ");
 11   fflush(stdout);//强制刷新缓冲区
 12   char buf[1024]={0};
 13   fgets(buf,sizeof(buf)-1,stdin);//获取输入的命令
 14  if(strlen(buf)==0)//若没有输入则继续输出提示框
 15  {
 16 continue;
 17  }
 18 
 19  printf("%s\n",buf);//读取到待替换的程序
 20  pid_t pid =fork();
 if(pid<0)
 22  {
 23    
 24    continue;
 25  }
 26  else if(pid==0)
 27  {
 28 //区分命令程序和命令行参数,空格之前是命令行程序 空格后是命令行参数
 29 char * begin =buf;
 30 char * end =buf;
 31 char * argv[1024]={0};
 32 int pos=0;
 33 while(*end !='\0')
 34 {
 35 while(*end !=' '&&*end !='\0')                                                               
 36 {
 37   end++;
 38 }
 39 argv[pos++]=begin;
 40 if(*end=='\0')
 {
 42  break; 
 43 }
 44 else 
 45 {
 46 *end ='\0';
 47 end++;
 48 begin =end;
 49 }
 50 }
 51 int i =0;
 52 for(i=1;i<pos;i++)
 53 {
 54   printf("argv[%d]:%s\n",i,argv[i]);
 55 }                                                                                            
 56 //进程程序替换
 57 exit(1);
 58 } 
 59 else 
 60  {
     //father
 62    wait(NULL);
 63  }
 64 }
 65 return 0;
 66  
 67 } 

九、Linux中的基础IO是什么意思?

IO就是input output的缩写,Linux的基础io就是指在linux操作系统中面向文件基础的读写操作。

1、c语言的文件操作接口(都是库函数)

1、打开文件函数
**FILE *fopen(const char path, const char mode);
path:带路径的文件名称
mode:读取文件的属性
r:可读不可写,文件不存在则报错
r+:以读写方式打开,文件不存在则报错
w:以可写方式打开,但是不能读,文件不存在则创建,文件存在则清空文件已有内容
w+:以读写方式打开,文件不存在则创建,文件存在则清空文件已有内容
a:追加写,不可读,文件不存在则创建,在文件末尾进行追加写
a+:可读追加写,文件不存在则创建,在文件末尾进行追加写

2、关闭文件函数
int fclose(FILE*fp);
关闭文件流指针,

3、读取文件函数
**size_t fread(void ptr, size_t size, size_t nmemb, FILE stream);
ptr:保存为用户准备的一块缓冲区内存,用于保存读取的数据
size:块的大小
nmemb:块的个数
stream:文件流指针,标识从哪儿开始读,
在这里插入图片描述
读取成功:
在这里插入图片描述
4、写入文件函数
**size_t fwrite(const void ptr, size_t size, size_t nmemb,FILE stream);
ptr:要写入文件中的内容
size:块的大小,单位字节
nmemb:块的个数
stream:文件流指针,标识从哪儿开始写,
在这里插入图片描述
写入成功:
在这里插入图片描述

5、对文件流指针进行操作,修改文件流指针在某个操作之后的位置
*int fseek(FILE stream, long offset, int whence);
stream:文件流指针
offset:偏移量,单位字节
whence:初始值
SEEK_SET:文件的头部
SEEK_CUR:当前文件流指针的位置
SEEK_END:文件的尾部

2、系统调用文件接口

open/close/read/write/llseek
1、int open(const char *pathname, int flags);
pathname:带打开的文件
flags:函数属性(有且只有一个是互斥的)
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:读写
与以上的属性以 | 符号组合使用(返回一个正整数,含义为文件描述符)
将属性以按位与的方式进行使用
O_CREAT:文件不存在则打开(打开的属性添加一个,八进制数字加上)
O_TRUNC:截断文件
O_APPEND:追加
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
例子:
以可读的方式打开文件

#include<stdio.h>
  2 #include<fcntl.h>
  3 int main()
  4 {
  5  int fd = open("./1.txt",O_RDONLY);//以可读方式打开文件的返回值
  6   if(fd < 0)    //小于0创建失败                                                                                       
  7   {
  8 perror("open");
  9 return 1;
 10   }
 11   printf("fd is %d",fd);//打开成功读出返回值
 12 
 13     return 0;
 14 }

3、什么是文件描述符&文件流指针?

2、close(int fd)fd:文件描述符
ssize_t read(int fd,void*buf,size_t count);
读取文件
fd:文件描述符
buf:把读到的内容放到buf这个缓冲区中
count:最大能读多少个字节,就是buf的大小,预留一个\0的位置
返回值:

0 读取的字符数
<0 读取失败
文件描述符就是指向某个文件的一个整数
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

3、ssize_t write(int fd, const void *buf, size_t count);
写入文件
fd :文件描述符
buf:写入到文件当中的内容
count:写入的字节数量
返回值:真正写入文件的内容

0:写入成功
<0:写入失败
在这里插入图片描述
在这里插入图片描述

4、off_t lseek(int fd, off_t offset, int whence);
当往文件内写入内容之后此时文件流指针是指向文件末尾的,因此要读取文件是不行的,所以此时要将文件的指针设置到想要读取内容的开头
fd:文件描述符
offset:偏移量
whence:
SEEK_SET
SEEK_CUR
SEEK_END
在这里插入图片描述
在这里插入图片描述

文件描述符

创建一个进程就是创建一个task_struct结构体,文件描述符是fd_arrat数组的下标,是正整数,通过文件描述符我们能找到储存在磁盘上的文件,文件描述符的打开原则是最小位占用原则,当最小位置被占用之后继续往下占用位置
在这里插入图片描述

怎么查看进程最大可以打开多少个文件描述符

可以通过命令ulimit -a 查看一个进程最大可以打开多少个文件描述符
使用ulimit -n可以改变数值
在这里插入图片描述

文件流指针是什么?与文件描述符有什么联系与不同?

1、文件流指针是一个结构体,包含着正整数的文件描述符,文件描述符是fd_array数组的下标
2、文件流指针维护着读写缓冲区,刷新缓冲区时刷新的是c库的缓冲区
在这里插入图片描述

4、怎么查询linux的内核版本?

命令:
cat /etc/redhat-release
uname -r
在这里插入图片描述

5、重定向

重定向能够将进程的生成结构直接导入另一个进程当中,可以清除另一个进程内容生成也可以直接将生成内容输出到另一个进程中。
1、重定向命令:

将某个指令的结果重定向到另一个进程中,原有的内容被清除
将 ps aux 的输出重定向到1.txt文件夹中

追加重定,原有的内容不被删除,直接增加内容
在这里插入图片描述
2、重定向的原理
在这里插入图片描述
3、代码重定向
int dup2(int oldfd, int newfd);
newfd拷贝oldfd
重定向的原理

6、静态库和动态库

什么是动态库?动态库和静态库的区别是什么?
动态库是为了保护源码的隐私性,不让他人查看源码,进而产生的程序包,使别人可以使用动态库直接产生可执行程序,在实际应用中应用于功能繁复的大型程序中,便于多人对程序的修改提交。动态静态库的不同体现子在程序的链接方式不同,静态库是在链接阶段使用静态链接将汇编生成的目标文件.o与引用到的库一同打包到可执行文件中,动态库动态库在程序编译时并不会链接到目标代码中,而是在程序运行时被载入,用户只用更新动态库就能实现对整个程序的更新。
1、动态库在不同环境下的格式:
win:后缀为.dll,
linux:后缀为.so,前缀为lib
在这里插入图片描述

2、如何生成/编译动态库:gcc/g++
-shared:生成动态库
-fPIC生成与位置无关的代码
命令范式:
gcc/g++ [source code]-shared -fPIC -o lib[动态库名称].so
gcc/g++ [source code] -o [可执行程序] -L [动态库所在的路径] -l[动态库名称]
在这里插入图片描述
编译动态库的命令
在这里插入图片描述
动态库编译成功
在这里插入图片描述
main函数的编译
在这里插入图片描述
可执行程序寻找依赖的动态库
命令:
ldd+可执行程序名称:查看程序依赖的所有动态库
在这里插入图片描述
1、静态库在不同运行环境下的格式:
win:后缀为.lib
linux:后缀为.a,前缀为lib
2、如何生成/编译静态库:ar -rc lib[静态库名称].a [依赖的汇编文件]
在这里插入图片描述
使用命令范式:
gcc/g++ [source code] -o [可执行程序] -L [静态库所在的路径] -l[静态库名称]
区分动态链接和静态链接的方法:
在编译的时候是否加-static

7、文件系统

文件在磁盘中的存储是离散存储的,分区分块,以节点的格式在磁盘中储存信息。
在这里插入图片描述
在这里插入图片描述

8、软硬连接

1、软链接:
软连接就是给文件创建了一个快捷方式
2、创建软链接文件
ln -s [程序名称] [生成程序的名称]
在这里插入图片描述
源文件与软连接相互影响
2、硬链接
1、硬链接相当于文件的备份
1、创建硬链接文件
ln [源程序名称] [生成文件的名称]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值