程序和硬件之间隔了一个内核,比如程序要想加载磁盘上的数据,那么需要内核来完成,将程序加载到内核的pagecache中(4k),然后用户空间的所有程序都可以访问这个pagecache,如果有程序修改了这个数据,那么就会标记位ditry
两个程序可以打开相同的文件,但是每个程序的文件描述fd符会自动维护着指针,文件在内容中的数据是一份的
每个文件有多个文件描述符,每个文件描述符可以理解为一个指针,任何程序都有0、1、2文件描述符,0表示标准输入、1表示标准输出、2表示错误
cd /proc
进入内核映射目录,可以看到内核的一些变量属性都在里面挂载,每一个数字都是一个进程的id号,都被映射成了文件
$$是当前bash的pid(端口),也就是说当前命令行程序的端口号
除了$$还可以通过$BASHPID 来获得
这两个都可以获取到,区别是第一个优先级高,第二个优先级低
进入到这个j进程之后,进入到fd可以看到程序的描述符
lsof -op $$可以看当前$$进程文件描述符的细节
就可以可看到这个进程的文件描述符的信息了
可以看到进程是一个文件,然后进程的属性也是文件,一切皆文件
重定向不是命令,而是机制
0表示标准输入,1表示标准输出,那么我们可以使用重定向的方式对其进行修改,比如ls标准输入是当前的目录,表示输出是控制台,我们可以对其进行修改,如下所示:
如上所示我们将1标准输出改为了1.txt,这样ls的的输出就不会到控制台了,而是会到1.txt中,需要注意1和>之间必须紧密连接
>表示输出
<表示输入
我们可以将cat AA.JAVA的文件内容的标注输出屏幕重定向到1.txt
输入read a,它就会阻塞了,然后我们输入一个内容,然后按换行符,read会换行符特别敏感,只要有换行符就表示read完成了。
如上所示echo $a的结果就是123了。说明a 的标准输入是控制台,我们可以对其进行改变
如上所示,我们将a的标准输入改为了1.txt,我们输出a的时候,只有1.txt的第一行,这是因为read对换行符敏感,一旦有换行符,就会赋值成功。
ls可以同时查看多个目录
如上所示,ls分别查看了./和一个随便写的目录,所以一个正常输出,另外一个报错了,我们可以使用重定向,对正常输出的重定向到一个文件,对不正常输出的重定向到另外一个文件中,如下所示:
如上所示流还是可以进行传递的
标准输出流指向1.txt,而错误输出流指向1,这样错误的也会输出到1.txt了,需要注意的是2>$ 1,如果没有$会把1当作一个普通的文件看待。
如果ls ./ ./aaaa 2>& 1 1>1.txt就会有问题,因为2>& 1,此时1就是标准输出流,那么就会错误输出到控制台,1> 1.txt就会将标准输出流重定向到1.txt,所以就是错误的到控制台,正确的到1.txt,所以需要注意顺序。
管道 |
head -10 1.txt
可以显示1.txt中的前10行
tail -10 1.txt
可以显示1.txt中的后10行
head -10 1.txt | tail -1
可以显示第10行
父子进程
通过pstree可以看到当前所有进程的进程树,同时我们可以看到倒数第二行,我们当前所处的bash进程下面开启了一个pstree进程,那么pstree进程就是bash的子进程,前面介绍过我们可以通过echo $$获取到当前的进程pid,下面我们在当前的进程下面再开启一个bash进程
我们可以看到,我们进入了bash下面的bash进程,那么此时的pid就和父的不一样了,下面我们再通过pstree来看一下:
如下所示,我们是在bash进程下面开启了bash进程,然后下面有pstree进程。要想退出当前的进程,可以输入exit
我们当前是在bash进程中,那么我们就可以写bash程序,比如之前的read a,还可以给传输赋值,如下所示:
但是需要注意当前的x是定义在当前的进程的,而子进程是获取不到的。
这说明进程之间是隔离的,如果要想让子进程获取到父进程的,需要在父进程中进行export
如上所示,子进程就获取到了
bash命令中还可以定义代码块,如下所示:
注意{}和代码之间必须要有空格,一个代码必须有;作为结束
如上代码所示,{ x=200 ; echo "fuzhi" ; } | cat 这个表示给x赋值200,然后输出fuzhi,输出通过流传递给了cat,cat接收到之后输出给标注输出流控制台,所以屏幕输出fuzhi了
,但是此时输出x就是100,而不是200
这是因为bash程序在执行的时候,首先发现了管道 | ,那么它会自动地将管道两边设置为子进程,所以x=200,只是在子进程中执行的,不会对父进程有任何影响,|具有进程间的流动能力,所以虽然是两个子进程,但是也依然可以进行数据的流动
是不是真的开启子进程呢,我们来验证一下
如上所示,我们输出管道左边的进程号,发现确实和当前进程的pid号不一致,那么说明确实开启了一个子进程。需要注意的是左边不能使用echo $$,这是因为echo $$的优先级相对较高,这样bash解释执行的时候,就会先执行echo $$,然后才看到管道|,这样echo $$的结果就是父进程pid了。
在父进程中:
开启两个子进程,左边子进程输出当前子进程的pid,然后读取s,然后右进程接收左进程的输入,然后输出到控制台,然后输出右进程的PID,然后读取y。
执行之后,我们可以看到只执行到左进程的read就阻塞了,下面我们看一下父进程中是否创建了这两个子进程,如下所示:
如下所示,我们可以看到父进程27414下面有两个子进程27754和27755,然后我们去每个进程中看看文件描述符:
我们可以看到,第一个左进程的标准输出已经是管道了,而第二个右进程的标准输入也是管道了,这样就和之前对接起来了。
socket
如下所示,我们可以看到当前进程的文件描述符8的输入和输出都是socket了
虚拟文件系统
cd /就会进入到根目录
然后ll就可以看到根目录下面的目录
在这个虚拟文件系统中有三个分区,1、2、3,如下所示:
使用df命令可以看到当前的目录挂载到哪个分区中,其中/挂载到/dev/...中,那么/下面的所有子目录也是挂在到/dev/...中的,而/boot是引导程序,它会挂在到/dev/sda1下面
通过这个就是说linux的目录会挂载到虚拟的磁盘上。
一切皆文件,这个意思就是说,真实的目录可以是文件,摄像头也可以是文件,打印机也是文件,既然是文件那么就可以使用IO流了。文件是有类型的,常用的类型有:
1、-表示可执行的
2、d是目录
3、b是块设备(硬盘)
4、c是字符设备(键盘,socket)
5、p是管道
6、eventpoll,epoll的内存区域
7、l是连接的
从一个地方能够读数据,不受限制,想读哪就读哪,这个就是块设备
我首先通过touch命令创建a.txt,然后通过ln可以建立一个a.txt的硬连接b.txt,然后通过stat命令看这两个文件的详细信息
可以看到两个文件有相同的Inode。需要知道的是a.txt和b.txt虽然有不同的路径,但是它们却指向相同的物理地址,修改任意一份,另外一个打开之后,也会发生变化,删除一个,另外一个没有影响。
如上所示可以通过ln -s建立a.txt的软连接c.txt,软连接可以理解为指向了a.txt,所以一旦a.txt被删除,那么c.txt也没有意义了。
如果看二者的Inode我们可以看到二者已经不一样了,修改任意一方,另外一方也会有任何变化