为了从更深层次了解计算机的IO ,需要对计算的文件系统进行深入学习,下边是本人的学习笔记,请大家一起参考,要是有说的不对的地方,请大家指正!
Linux 中的文件系统大概分为以下几类
-: # 普通文件类型
l:#软/硬连接类型
d:目录类型
s:socket
p:pipline
b:块设备
c:字符设备
1、普通文件类型 (-)
通常用户所接触到的文件,比如图形文件、数据文件、文档文件以及声音文件都属于这种文件,这种类型的文件是按照其内部结构又可分为纯文本文件(ASCII)、二进制文件(binary)、数据格式的文件(data)、各种压缩文件。
举个例子 🌰
在linux系统/opt文件夹中创建一个普通文本文件test.txt并将"test info" 写入改文件
[root@node20 opt]# touch test.txt
[root@node20 opt]# echo "test info" > test.txt
使用ll
指令查看该文件夹下内容
[root@node20 opt]# ll
total 4
drwx--x--x 4 root root 28 May 25 09:37 containerd
-rw-r--r-- 1 root root 10 Sep 23 22:22 test.txt
[root@node20 opt]#
其中前排的 -rw-r--r--
的第一个 -
就表示普通文件类型
这里提一下文件的权限信息
第一位表示文件类型,剩下的三位一组,分别表示文件的所有者权限,文件所有组权限,其他人的权限
r
是read的缩写表示读取
w
是write的缩写表示可写
x
表示文件可以被执行
-
表示响应的权限还没被授予
后边的数字是该文件被指向的次数
2、软/硬连接
是一种特殊文件,指向一个真实存在的文件链接,类似于Windows下的快捷方式,链接文件的不同,又可分为硬链接文件和软链接文件(也称符号连接) 还拿刚才提到的test.txt 来举例子,我们分别来为test.txt创建一个硬链接和软连接
[root@node20 opt]# ln test.txt test1.txt
[root@node20 opt]# ln -s test.txt test2.txt
然后ll
查看文件夹下内容
[root@node20 opt]# ll
total 8
drwx--x--x 4 root root 28 May 25 09:37 containerd
-rw-r--r-- 2 root root 10 Sep 23 22:22 test1.txt
lrwxrwxrwx 1 root root 8 Sep 23 22:34 test2.txt -> test.txt
-rw-r--r-- 2 root root 10 Sep 23 22:22 test.txt
其中的test1.txt为硬链接,test2.txt 为软连接
我们可以发现其中的test.txt 和text1.txt 文件的被指向次数都相同,都为2
然后我们通过stat
指令查看文件的详细信息
[root@node20 opt]# stat test.txt
File: ‘test.txt’
Size: 10 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 18089313 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-09-23 22:21:49.315836748 -0400
Modify: 2022-09-23 22:22:01.452007290 -0400
Change: 2022-09-23 22:33:54.410503915 -0400
Birth: -
这里我们记住他的Inode 编号为:18089313
然后我们在查看test1.txt 的详细信息
[root@node20 opt]# stat test1.txt
File: ‘test1.txt’
Size: 10 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 18089313 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-09-23 22:47:25.714321077 -0400
Modify: 2022-09-23 22:22:01.452007290 -0400
Change: 2022-09-23 22:33:54.410503915 -0400
Birth: -
发现test1.txt 的Inode编号和test.txt 的编号完全相同
软连接的编号是不是一样的呢?我猜应该是不一样的吧,因为他们的被指向次数不一样啊,test2.txt 被指向了一次,test.txt 和test1.txt都被指向了两次,我们来用命令确认一下吧
[root@node20 opt]# stat test2.txt
File: ‘test2.txt’ -> ‘test.txt’
Size: 8 Blocks: 0 IO Block: 4096 symbolic link
Device: fd00h/64768d Inode: 16785378 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-09-23 22:34:49.687244568 -0400
Modify: 2022-09-23 22:34:02.762618594 -0400
Change: 2022-09-23 22:34:02.762618594 -0400
Birth: -
通过命令我们可以出test2.txt 和text.txt 的Inode编号是不一样的
我们尝试修改源文件text.txt 的内容,发现test1.txt 和test2.txt 的内容会同步修改。那软连接和硬连接有什么区别呢???
下边尝试删除源文件test.txt,发现test1.txt 可以正常打开,test2.txt 文件报错
[root@node20 opt]# rm -f test.txt
[root@node20 opt]# ll
total 4
drwx--x--x 4 root root 28 May 25 09:37 containerd
-rw-r--r-- 1 root root 10 Sep 23 22:22 test1.txt
lrwxrwxrwx 1 root root 8 Sep 23 22:34 test2.txt -> test.txt
[root@node20 opt]# cat test2.txt
cat: test2.txt: No such file or directory
[root@node20 opt]# cat test1.txt
test info
[root@node20 opt]#
3、目录类型
用于存放文件名以及其相关信息的文件,是内核组织文件系统的基本节点。目录文件可以包含下一级文件目录或者普通文件,在Linux中,目录文件是一种文件。
我们返回根目录,然后是用ll
命令查看,以d
打头的就是目录类型
[root@node20 opt]# cd /
[root@node20 /]# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@node20 /]# ll
total 16
lrwxrwxrwx. 1 root root 7 Sep 25 2021 bin -> usr/bin
dr-xr-xr-x. 5 root root 4096 Sep 25 2021 boot
drwxr-xr-x 20 root root 3240 Sep 23 22:14 dev
drwxr-xr-x. 77 root root 8192 Sep 23 22:14 etc
drwxr-xr-x. 2 root root 6 Apr 11 2018 home
lrwxrwxrwx. 1 root root 7 Sep 25 2021 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Sep 25 2021 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 6 Apr 11 2018 media
drwxr-xr-x. 3 root root 18 Sep 25 2021 mnt
drwxr-xr-x. 3 root root 58 Sep 23 22:57 opt
dr-xr-xr-x 112 root root 0 Sep 23 22:14 proc
dr-xr-x---. 4 root root 178 Sep 23 22:54 root
drwxr-xr-x 24 root root 660 Sep 23 22:14 run
lrwxrwxrwx. 1 root root 8 Sep 25 2021 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Apr 11 2018 srv
dr-xr-xr-x 13 root root 0 Sep 23 22:14 sys
drwxrwxrwt. 10 root root 240 Sep 23 22:15 tmp
drwxr-xr-x. 13 root root 155 Sep 25 2021 usr
drwxr-xr-x. 19 root root 267 Sep 25 2021 var
4、socket 类型
说明socket类型,需要一个前提小知识:fd(文件描述符),任何一个程序都有的三个文件描述符
0:标准输入
1:标准输出
2:错误输出
他们是在Linux操作系统中怎么体现的呢?
[root@node20 /]# cd /proc/$$/fd
[root@node20 fd]# ll
total 0
lrwx------ 1 root root 64 Sep 23 22:17 0 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 23 22:17 1 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 23 22:17 2 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 23 23:05 255 -> /dev/pts/0
命令解释:
/proc 这个目录是Linux系统下一个很重要的目录。 它跟/etc, /home等这些系统目录不同, 它不是一个真正的文件系统, 而是一个虚拟的文件系统。 它不存在于磁盘, 而是存在于系统内存中,proc以文件系统的方式为访问系统内核的操作提供接口
$$
查看当前的进程号
不同的进程中有不同的文件描述符,不同的文件描述符中保存着针对一个文件不同的偏移量
上面的话很重要哦,下面通过一个实验来证明他
-----------------------------------分割线--------------------------------------------------
创建一个文件并随便写入些内容
[root@node20 opt]# vim testfd.txt
[root@node20 opt]# cat testfd.txt
dfi
sdfsdfadf
1
123
123
123
123
[root@node20 opt]#
我们创建一个文件描述符,去读取这个文件
exec 7< /opt/testfd.txt
[root@node20 opt]# cd /proc/$$/fd
[root@node20 fd]# ll
total 0
lrwx------ 1 root root 64 Sep 23 22:17 0 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 23 22:17 1 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 23 22:17 2 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 23 23:05 255 -> /dev/pts/0
lr-x------ 1 root root 64 Sep 23 22:17 7 -> /opt/testfd.txt
我们看到了"7"号文件描述符已经存在了
我们使用lsof
这个命令来查看文件描述符的详细内容
[root@node20 fd]# lsof -op $$
COMMAND PID USER FD TYPE DEVICE OFFSET NODE NAME
bash 1428 root cwd DIR 0,3 21757 /proc/1428/fd
bash 1428 root rtd DIR 253,0 64 /
bash 1428 root txt REG 253,0 50333247 /usr/bin/bash
bash 1428 root mem REG 253,0 50333147 /usr/lib/locale/locale-archive
bash 1428 root mem REG 253,0 563 /usr/lib64/libnss_files-2.17.so
bash 1428 root mem REG 253,0 545 /usr/lib64/libc-2.17.so
bash 1428 root mem REG 253,0 551 /usr/lib64/libdl-2.17.so
bash 1428 root mem REG 253,0 64684 /usr/lib64/libtinfo.so.5.9
bash 1428 root mem REG 253,0 520 /usr/lib64/ld-2.17.so
bash 1428 root mem REG 253,0 16800876 /usr/lib64/gconv/gconv-modules.cache
bash 1428 root 0u CHR 136,0 0t0 3 /dev/pts/0
bash 1428 root 1u CHR 136,0 0t0 3 /dev/pts/0
bash 1428 root 2u CHR 136,0 0t0 3 /dev/pts/0
bash 1428 root 7r REG 253,0 0t0 18089326 /opt/testfd.txt
bash 1428 root 255u CHR 136,0 0t0 3 /dev/pts/0
[root@node20 fd]#
ps:如果有提示-bash: lsof: command not found
这个错误的小伙伴,请先用yum install lsof -y
这个命令来安装lsof
我们看到了我们创建的"7"号文件描述符,他的OFFSET 指向了0,说明没有读取到文件
接下来我们使用 read
命令来读取这个文件
[root@node20 fd]# read myinfo 0<& 7
read 会读取 7号文件描述符中的内容到myinfo 这个环境变量中,我们来打印这个环境变量
[root@node20 fd]# echo $myinfo
dfi
[root@node20 fd]#
myinfo 中的内容为dfi ,这是为啥呢?
read 会读到以换行符结束前的内容,因为我们在创建文件的时候,写入的第一行内容就是dfi
我们再次查看文件描述符的OFFSET
[root@node20 fd]# lsof -op $$
COMMAND PID USER FD TYPE DEVICE OFFSET NODE NAME
bash 1592 root cwd DIR 0,3 27327 /proc/1592/fd
bash 1592 root rtd DIR 253,0 64 /
bash 1592 root txt REG 253,0 50333247 /usr/bin/bash
bash 1592 root mem REG 253,0 50333147 /usr/lib/locale/locale-archive
bash 1592 root mem REG 253,0 563 /usr/lib64/libnss_files-2.17.so
bash 1592 root mem REG 253,0 545 /usr/lib64/libc-2.17.so
bash 1592 root mem REG 253,0 551 /usr/lib64/libdl-2.17.so
bash 1592 root mem REG 253,0 64684 /usr/lib64/libtinfo.so.5.9
bash 1592 root mem REG 253,0 520 /usr/lib64/ld-2.17.so
bash 1592 root mem REG 253,0 16800876 /usr/lib64/gconv/gconv-modules.cache
bash 1592 root 0u CHR 136,1 0t0 4 /dev/pts/1
bash 1592 root 1u CHR 136,1 0t0 4 /dev/pts/1
bash 1592 root 2u CHR 136,1 0t0 4 /dev/pts/1
bash 1592 root 7r REG 253,0 0t4 18089331 /opt/testfd.txt
bash 1592 root 255u CHR 136,1 0t0 4 /dev/pts/1
[root@node20 fd]#
发现7号文件描述符的OFFSET 已经变成4了
我们在打开一个新的窗口连接到虚拟机,进入到/proc/$$/fd
这个目录下,
使用ll
查看就没有7号这个文件描述符,
我们也可以把上边创建文件描述符,读取文件内容的命令在新窗口执行一次,对比发现,他们的不同的文件描述符的OFFSET 是隔离的
-----------------------------------分割线--------------------------------------------------
补充完了上边的知识,现在可以演示socket 类型了
[root@node20 /]# exec 9<> /dev/tcp/www.baidu.com/80
[root@node20 /]# lsof -op $$
COMMAND PID USER FD TYPE DEVICE OFFSET NODE NAME
bash 1618 root cwd DIR 253,0 64 /
bash 1618 root rtd DIR 253,0 64 /
bash 1618 root txt REG 253,0 50333247 /usr/bin/bash
bash 1618 root mem REG 253,0 573 /usr/lib64/libresolv-2.17.so
bash 1618 root mem REG 253,0 561 /usr/lib64/libnss_dns-2.17.so
bash 1618 root mem REG 253,0 50333147 /usr/lib/locale/locale-archive
bash 1618 root mem REG 253,0 563 /usr/lib64/libnss_files-2.17.so
bash 1618 root mem REG 253,0 545 /usr/lib64/libc-2.17.so
bash 1618 root mem REG 253,0 551 /usr/lib64/libdl-2.17.so
bash 1618 root mem REG 253,0 64684 /usr/lib64/libtinfo.so.5.9
bash 1618 root mem REG 253,0 520 /usr/lib64/ld-2.17.so
bash 1618 root mem REG 253,0 16800876 /usr/lib64/gconv/gconv-modules.cache
bash 1618 root 0u CHR 136,0 0t0 3 /dev/pts/0
bash 1618 root 1u CHR 136,0 0t0 3 /dev/pts/0
bash 1618 root 2u CHR 136,0 0t0 3 /dev/pts/0
bash 1618 root 9u IPv4 28496 0t0 TCP node20:54904->39.156.66.14:http (ESTABLISHED)
bash 1618 root 255u CHR 136,0 0t0 3 /dev/pts/0
[root@node20 /]#
我们定义了9号文件描述符,并将9号文件描述符的输入输出指向了www.baidu.com 的80 端口,我们就看到了9号文件描述符是个TCP 连接
5、管道类型
想要演示管道类型,也需要几个前提知识
$$
可以表示当前进程的pid
$BASHPID
也可以表示当前进程的pid
|
管道可以衔接两个命令
{ }
代码块
猜猜看下边的代码会输出什么?
[root@node20 /]# x=15
[root@node20 /]# echo $x
15
[root@node20 /]# { x=20;echo "asdf"; }|cat
asdf
[root@node20 /]# echo $x
定义了一个临时变量x,并赋值15,然后在代码块中将x赋值20,并将"asdf" 交给了管道由cat 进行输出,最后取值x,x的值会是15还是会是20呢?
15
答案是15
!!!,让我们来看看为什么?
|
管道左边会开启一个子进程,右边也会开启一个子进程,我们在当前的进程将x赋值为了15,在子进程中修改了x的值,由于进程间是隔离的我们在主进程中打印x的值,依然是15。
下边的实验来证明|
会开启两个子进程
-------------------------------------分割线----------------------------------------------
首先查看当前进程
[root@node20 /]# echo $$
1618
当前的进程pid 为1618
然后管道左边打印当前进程,管道右边进行输出
[root@node20 /]# echo $$ | cat
1618
what?什么情况,这里也是 1618,刚才不是说好的左边会开启一个单独的进程吗?现在翻车了???
没有翻车,这里只是为了证明 $$
的优先级比较高,linux 会先执行管道左边的$$
然后输出
刚刚我们说过了$BASEHPID
也能打印当前进程,我们换个命令试一下
[root@node20 /]# echo $BASHPID |cat
1686
结果已经出来了,管道左边的进程是1686,说明管道左边会开启一个新的进程
-------------------------------------分割线----------------------------------------------
咱们的目的是为了证明linux 有管道这种文件类型
我们来看一下下边的程序
[root@node20 /]# { echo $BASHPID; read x; } | { cat ; ehco $BASHPID ; read z ; }
1713
我们用管道连接了两个代码块,左边的代码块打印了当前的进程id,也就是新的进程id,然后用read 命令进行了阻塞;管道右边将左边的进程id进行了打印,同时也打印了个右边的新的进程id,同样使用read 进行了阻塞;由于read 的阻塞,右边的进程没有输出出来,通过上边的实验我们已经知道了,当前标签页的进程id为1618,我们重新开一个新的标签页,去查询进程号为1618的进程
[root@node20 /]# ps -ef |grep 1618
root 1618 1616 0 Sep23 pts/0 00:00:00 -bash
root 1713 1618 0 01:37 pts/0 00:00:00 -bash
root 1714 1618 0 01:37 pts/0 00:00:00 -bash
root 1738 1720 0 01:42 pts/2 00:00:00 grep --color=auto 1618
[root@node20 /]#
我们可以看到1618 产生了两个新的子进程,分别是 1713 和1714
然后我们使用lsof
命令查看这两个子进程的文件描述符
[root@node20 /]# lsof -op 1713
COMMAND PID USER FD TYPE DEVICE OFFSET NODE NAME
bash 1713 root cwd DIR 253,0 64 /
bash 1713 root rtd DIR 253,0 64 /
bash 1713 root txt REG 253,0 50333247 /usr/bin/bash
bash 1713 root mem REG 253,0 573 /usr/lib64/libresolv-2.17.so
bash 1713 root mem REG 253,0 561 /usr/lib64/libnss_dns-2.17.so
bash 1713 root mem REG 253,0 50333147 /usr/lib/locale/locale-archive
bash 1713 root mem REG 253,0 563 /usr/lib64/libnss_files-2.17.so
bash 1713 root mem REG 253,0 545 /usr/lib64/libc-2.17.so
bash 1713 root mem REG 253,0 551 /usr/lib64/libdl-2.17.so
bash 1713 root mem REG 253,0 64684 /usr/lib64/libtinfo.so.5.9
bash 1713 root mem REG 253,0 520 /usr/lib64/ld-2.17.so
bash 1713 root mem REG 253,0 16800876 /usr/lib64/gconv/gconv-modules.cache
bash 1713 root 0u CHR 136,0 0t0 3 /dev/pts/0
bash 1713 root 1w FIFO 0,9 0t0 36649 pipe
bash 1713 root 2u CHR 136,0 0t0 3 /dev/pts/0
bash 1713 root 9u IPv4 28496 0t0 TCP node20:54904->39.156.66.14:http (CLOSE_WAIT)
bash 1713 root 255u CHR 136,0 0t0 3 /dev/pts/0
[root@node20 /]#
我们可以看到1713的1号文件描述符也就是标准输出,TYPE 类型成了一个FIFO的管道类型;
我们继续使用lsof
命令查看1714的文件描述符
[root@node20 /]# lsof -op 1714
COMMAND PID USER FD TYPE DEVICE OFFSET NODE NAME
bash 1714 root cwd DIR 253,0 64 /
bash 1714 root rtd DIR 253,0 64 /
bash 1714 root txt REG 253,0 50333247 /usr/bin/bash
bash 1714 root mem REG 253,0 573 /usr/lib64/libresolv-2.17.so
bash 1714 root mem REG 253,0 561 /usr/lib64/libnss_dns-2.17.so
bash 1714 root mem REG 253,0 50333147 /usr/lib/locale/locale-archive
bash 1714 root mem REG 253,0 563 /usr/lib64/libnss_files-2.17.so
bash 1714 root mem REG 253,0 545 /usr/lib64/libc-2.17.so
bash 1714 root mem REG 253,0 551 /usr/lib64/libdl-2.17.so
bash 1714 root mem REG 253,0 64684 /usr/lib64/libtinfo.so.5.9
bash 1714 root mem REG 253,0 520 /usr/lib64/ld-2.17.so
bash 1714 root mem REG 253,0 16800876 /usr/lib64/gconv/gconv-modules.cache
bash 1714 root 0r FIFO 0,9 0t0 36649 pipe
bash 1714 root 1u CHR 136,0 0t0 3 /dev/pts/0
bash 1714 root 2u CHR 136,0 0t0 3 /dev/pts/0
bash 1714 root 9u IPv4 28496 0t0 TCP node20:54904->39.156.66.14:http (CLOSE_WAIT)
bash 1714 root 255u CHR 136,0 0t0 3 /dev/pts/0
[root@node20 /]#
1714进程的0号文件描述符也就是标准输入文件描述符也是一个FIFO类型的管道,并且他们的NODE 编号都是36649
通过以上的实验证明了linux 中pipline 的文件类型
6、块设备
块设备文件 : 就是存储数据以供系统存取的接口设备,简单而言就是硬盘。例如一号硬盘的代码是 /dev/hda1等文件
块设备可以用df
命令进行查看
[root@node20 /]# df
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 919588 0 919588 0% /dev
tmpfs 931496 0 931496 0% /dev/shm
tmpfs 931496 9788 921708 2% /run
tmpfs 931496 0 931496 0% /sys/fs/cgroup
/dev/mapper/centos-root 17811456 2821672 14989784 16% /
/dev/sda1 1038336 198540 839796 20% /boot
tmpfs 186300 0 186300 0% /run/user/0
这里显示了文件的挂载信息,我的是虚拟机
块设备就是硬盘挂载的那些东西,运维用的会比较多,这里本文不再介绍。
7、字符设备
字符设备文件:即串行端口的接口设备,例如键盘、鼠标等等。
这里为了学习IO ,字符设备也略过了.....
8、额外的话
刚开始学习linux 的话,好多命令都记不住,推荐一下小的插件,在Utools 里边,名字就叫做linux ,可以随时查看linux 相关操作,这里放个gif吧