Linux:硬盘管理与文件系统

Linux:硬盘管理与文件系统

九月 16, 2019
当前设备屏幕尺寸过小,推荐使用PC模式浏览。

Preliminaries

请确保您对cdls等命令有了一定的了解,懂得使用--help参数,如ls --help查看所有命令的详细参数和使用帮助。

本文将可能会用到以下命令:

  • 基本操作:cdlsrmmkdirrmdirpwd
  • 文件创建、复制、移动删除:touchcpmvrm
  • 文件权限管理:chmodchownumask
  • 文件查看、读写:vivimgeditcat
  • 文件检索:findwhereiswhich
  • 用户管理:useraddusermodgroupadd
  • 磁盘管理:mountumountdfblkidfdiskln

您并不需要立刻掌握它们,但在本文中它们将可能会被用到,所以看完本文你将会学会这些指令的部分用法。

文件系统

Linux是基于多用户的系统,若管理不当,很容易造成文件的损坏等问题。因此文件系统值得进行学习和记录:

  • 文件的权限管理
  • Linux的目录配置、各个目录的意义等

注:由于部分内容需要权限才能操作,因此下文所有命令默认情况下均在root用户下进行操作。

  • 使用su root命令可以切换到root用户。

Linux系统的文件属性

使用cd /切换到主目录,键入命令ls -l,会得到以下内容:

1
2
3
4
5
6
(以下数据在 "ubuntu 16.04 STL" 得到)
drwxr-xr-x 2 root root 4096 626 20:16 bin
drwxr-xr-x 4 root root 4096 626 20:17 boot
drwxrwxr-x 2 root root 4096 626 20:10 cdrom
-rw------- 1 root root 9367552 627 22:21 core
......(略)

各列意义分别为:<文件权限> <链接数> <所属拥有者> < 所属用户组> <文件大小> <修改日期 月:日:(年)-时:分:> <文件名>

① 文件权限(permission)

此处显示的Linux的文件权限是一个10位的字符串,分为一个文件类型标识符和三组权限标识符,每组权限标识符有三位(rwx):

  • dev文件为例,其首位为【d】,表示这是一个目录(directory)——【d】【l】【-】【b】【c】分表表示“目录”、“链接”(link)、“文件”、“任意读写设备”(block)和“串口设备”(character)。

又例如,cd /dev查看sda文件的文件属性,会发现这是一个【b】文件。在Linux中,这是首位挂载的SATA硬盘,将在下文进行进一步的解读。

  • 权限标识符分为三种【r】(read,权限代值为4)、【w】(write,权限代值为2)、【x】(execute,权限代值为1)。
  • 一共有三组权限标识符。这三组权限标识符从左到右分别标示出了文件所有者、同用户组用户和其它人的权限。

如上文所显示的boot文件,它是一个目录,对于所有者root具有【rwx】(读写与执行)权限,对root用户组具有【rx】(读和执行),其它用户对其可以【rx】。

  • 需要注意的是,root用户对所有文件具有完全权限。也就是说root文件不受文件权限属性的限制。
  • 目录和文件的rwx并不具有相同的意义,如对于一个文件test.sh,【r】权限表示其可以通过vi test.sh打开并读取、【x】权限可以利用./test.sh直接执行;对于一个目录test,【r】权限指的是目录子文件读取,如ls指令、【x】权限实际上指的是目录访问(access directory),如cd ./test

文件属性的第二列表示有多少个文件链接到这个文件节点(inode),这部分内容跟Linux的软连接和硬链接有关。将在下文中进行解释。


Linux系统中的文件权限管理

本节将会介绍三种命令chmodchownchgrp

  • chgrp是change group的缩写,即改变文件所属用户组,我们使用chgrp --help查看帮助:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
用法:chgrp [选项]... 用户组 文件...
 或:chgrp [选项]... --reference=参考文件 文件...
Change the group of each FILE to GROUP.
With --reference, change the group of each FILE to that of RFILE.

-c, --changes like verbose but report only when a change is made
-f, --silent, --quiet suppress most error messages
-v, --verbose output a diagnostic for every file processed
--dereference affect the referent of each symbolic link (this is
the default), rather than the symbolic link itself
-h, --no-dereference affect symbolic links instead of any referenced file
(useful only on systems that can change the
ownership of a symlink)
--no-preserve-root do not treat '/' specially (the default)
--preserve-root fail to operate recursively on '/'
--reference=RFILE use RFILE's group rather than specifying a
GROUP value
-R, --recursive operate on files and directories recursively

The following options modify how a hierarchy is traversed when the -R
option is also specified. If more than one is specified, only the final
one takes effect.

-H if a command line argument is a symbolic link
to a directory, traverse it
-L traverse every symbolic link to a directory
encountered
-P do not traverse any symbolic links (default)
1
2
3
示例:
chgrp staff /u 将/u的属组更改为"staff"。
chgrp -hR staff /u 将/u及其子目录下所有文件的属组更改为"staff"。
  • chown的用途相当广,某种程度上可以直接替换chgrp指令。使用示例:chown -R user:usergroup /test可以把文件/test的所属用户和用户组修改为userusergroup,【-R】参数可以一并修改该目录下的所有文件。

  • chmod用于修改文件权限,支持一系列的正则匹配方式。用的更多的方式是使用权限代值的方式修改文件权限:chmod 735 /test表示分别赋予权限【rwx】【-wx】【r-x】给用户、用户组和其他人。

权限代值:r=4、w=2、x=1;如果要赋予用户【rwx】的权限,即: 4+2+1=7,首位填7。

chmod还支持正则的操作方式,如chmod u=rwx,go=rx就会赋予权限【rwx】【r-x】【r-x】。
chmod [options] <范围><操作符><权限符>[,<范围><操作符><权限符>... ] <文件或目录>

chmod指令的正则Mode表

范围 操作符 权限符
【u】(用户)、【g】(用户组)、【o】(其他人)、【a】(所有人) 【+】(添加)、【-】(减去)、【=】(设置) 【r】【w】【x】

文件目录与配置、管理

① Filesystem Hierachy Standard(FHS)

因为Linux是一个多用户系统,为了方便更多的用户能够较好的协同,对文件的存放做出了规定,即FHS。概览如下:

可分享(shareable) 不可分享(unshareable)
不变(static) /usr(软件) /etc(配置文件)
/opt(第三方辅助软件) /boot(内核与部署文件)
可变动(variable) /var/mail(邮箱) /var/run(程序脚本相关【PID】)
/var/spool/news(新闻组) /var/lock(程序单线程运行相关)

根目录存放标准:

目录 应放置文件目录
/bin 存放可执行文件的目录,如chmodcat
/boot Linux内核及其它启动文件
/dev 硬件接口相关的文件存放于此,如/dev/sda
/etc 系统主要的配置文件,如/etc/passwdetc/fstab
/lib 系统启动时及/bin中可执行文件会用到的函数库
/media 可删除的设备,如软盘、光盘等
/mnt 临时挂载到系统的文件
/opt 第三方辅助软件,即非发行版中对某功能所原生提供的软件
/run 系统启动时的各项程序脚本信息
/sbin 类似/bin,但这些脚本命令一般只有root用户配置整个系统时才会用到,如fdiskifconfig
/srv 网络服务的数据存放目录
/tmp 程序存放临时数据的目录
/usr 软件存放目录,详见下文
/var 可变数据的存放目录,详见下文
/home 每个用户的主目录
/lib 存放与/bin中文件格式不同的二进制文件,如64位数的库文件等
/root root用户的主目录

UNIX Software Resource(/usr):

目录 应放置文件目录
/usr/bin 所有一般用户都能执行的程序文件,发行版中基于/bin的文件通过链接会在该文件下都存在一份
/usr/lib 同上
/usr/local 系统管理员在本机安装的软件,一般时为了避免版本差异。如/bin中自带了python 2.7,你可以在此处存一份python 3.6的版本
/usr/sbin 非系统正常运行所需要的程序命令文件
/usr/share 存放可分享的只读文件,如/usr/share/man存放在线帮助文件、/usr/share/doc存放软件的说明文档等
/usr/src 代码文件
/usr/games 游戏文件
/usr/include C语言头文件

/var:

目录 应放置文件目录
/var/cache 程序运行过程中的缓存
/var/lib 程序运行过程中的依赖数据文件目录
/var/lock 程序运行过程中严格限制单线程使用的文件
/var/log 日志文件
/var/mail 邮箱文件
/var/run 程序运行后产生的PID会存放于此
/var/spool 队列数据,常用于跨程序调用时的缓存队列

② 文件目录管理

相对路径与绝对路径、路径标识符

1
2
3
4
5
.        当前层目录
.. 上一层目录
- 前一个目录
~ 用户的主目录
~root root用户的主目录

如,存在一个用户名为user的用户,执行cd ~命令将会进入到/home/user目录中、ls .将会列出当前目录所有的文件。

目录操作命令:

  • cd 切换目录,如cd /。其为【change directory】的缩写。
  • pwd 显示当前工作目录的绝对路径,其为【print working directory】的缩写。
  • mkdir 创建一个目录,如mkdir /data将会在根目录下创建一个/data文件夹。
  • rmdir 移除一个空目录。如果为非空目录,建议使用 rm -rf /data来移除一个非空目录/data

③ 文件的创建、复制、删除与移动

  • touch 实际上是修改文件的时间与日期,但经常用于创建一个新文件,如touch ./newfile.txt
  • cp复制文件,如把当前层级的文件A移动到根目录下:cp A /。常用的参数【-p】,表示连文件的权限一同拷贝过去;【-r】用于把一个目录及目录里的子文件一同拷贝;【-i】如果目标地址已存在,会进行确认操作的询问。
  • rm 删除文件。常用的如【-rf】,用于不询问的删除整个目录文件(由于该操作比较危险,请谨慎操作)。
  • mv 移动文件,相当于Windows中的剪切操作。

此处再补充一个指令:

  • umask用于指定、查看当前用户创建一个新文件时的默认权限。

键入umask -S

1
u=rwx,g=rwx,o=rx

对应的键入umask

1
0002

意思就是【others】缺了【w】(权限代值为2)。
使用命令umask 0022修改默认权限,再使用 umask -S 查看所设定的默认权限:

1
u=rwx,g=rx,o=rx

④ 文件的查找

  • which 命令可以查找一个可执行文件/脚本的位置,如which ls
  • find 可以在指定的目录中搜寻文件,如find /bin -name ls;该命令功能比较强大,可用【–help】查看详细的参数,此处不赘述,常用的指令如【-name】可以指定目标文件的名字。
  • whereis 该命令相较于find功能更简单,但速度较快,使用较简单;常用的参数如【-l】,可以指定要搜索的目录等。

⑤ 环境变量 $PATH

假如我有一个可执行文件存放在/usr/mybin中,我每次执行它时都要cd到这个文件夹然后再执行,就非常麻烦。在Windows中我们可以通过设置环境变量来告诉系统哪些路径下的文件是Shell的一级搜索目录,同样在Linux也有这个功能。

我们可以通过echo $PATH命令来查看环境变量:

1
/home/user/bin:/home/user/.local/bin:/data/public/env/anaconda3/bin

可以观察到其包含了多组环境变量,用【:】隔开来。对于每个用户在其主目录下都有一个.bashrc文件用以配置环境变量,我们可以通过vim ~/.bashrc来查看该文件,并通过

1
export $PATH=xxxxx:xxxxxx:xxxxxx

来设置环境变量。设置完毕后直接reboot重启系统或source ~./bashrc编译该文件即可刷新系统的环境变量。


文件链接

① 索引式文件系统

在Linux中常用的ext2/3/4文件系统格式中,inode记录了某个文件其数据在硬盘中实际存放的区块。相比FAT格式的文件系统,inode能够让硬盘更快的检索到文件数据,某种程度上避免了频繁进行磁盘碎片整理的需求。

inode的数据存储方式被称为索引式文件系统(index allocation),每个文件会申请使用一个inode号,该inode指向的硬盘区块记录了文件数据的所有存储区块和存储顺序,操作系统就能凭此一次性读取所有的数据。

1
2
3
4
5
6
(以下数据在 "ubuntu 16.04 STL" 得到)
(首位就是inode号)
6684673 drwxr-xr-x 2 root root 4096 626 20:16 bin
4849665 drwxr-xr-x 4 root root 4096 626 20:17 boot
7995393 drwxrwxr-x 2 root root 4096 626 20:10 cdrom
.......(略)

相对的,还会有一个超级区块(Super Block),记录了系统中所有已使用和未使用的inode号,根据ext2/3/4的不同,每个inode占位从128B到256B。

可以使用dumpe2fs指令查看ext文件系统的超级区块信息,如:sudo dumpe2fs /dev/sda。(如果硬盘较大,可以使用Crtl+zCtrl+c提前结束程序)

1
2
3
4
5
6
7
8
.......(略)
Group 6879: (Blocks 225411072-225443839) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
Checksum 0x4553, unused inodes 8192
Block bitmap at 224919567 (bg #6864 + 15), Inode bitmap at 224919583 (bg #6864 + 31)
Inode表位于 224927264-224927775 (bg #6864 + 7712)
32768 free blocks, 8192 free inodes, 0 directories, 8192个未使用的inodes
可用块数: 225411072-225443839
.......(略)

正因为有了inode,我们常说的【挂载】(mount)才有了意义。本质上,挂载操作是在向系统申请inode,通过给每个文件和目录分配inode,操作系统依靠inode寻找文件和鉴权,我们才能正常操作Linux系统。

② 硬链接与软(符号)链接

  • 软(符号)链接(Symbolic Link) 类似于Windows中的桌面快捷链接,它本身就是一个独立的文件,自身占用一个inode,但inode指向的数据是链接原文件的区块位置。
  • 硬链接(Hard Link) 与链接源文件占用了同一个inode,它本身知识在某个目录下新加了一条指向原inode的关联记录。

为了更好地分辨这两种链接方式的区别,我们进行以下操作:

  1. 使用touch a.txt指令创建一个新文件a.txt,并使用vim a.txt将该文件的内容改为字符串 "数据 "。(关于Vim的使用请查看帮助文档)
  2. 使用ls -licat a.txt查看相关内容,注意观察其inode号(926162 )和链接数(=1):
1
2
3
4
5
6
(base) root@Server:~/test$ ls -li
总用量 4
926162 -rw-rw-r-- 1 root root 7 630 18:11 a.txt

(base) root@Server:~/test$ cat a.txt
数据
  1. 使用ln a.txt hardlink_a创建一个硬链接,使用ls -li查看,可以看到二者inode号一致、文件大小皆为 77 且链接数皆变为了 22
1
2
3
4
(base) root@Server:~/test$ ls -li
总用量 8
926162 -rw-rw-r-- 2 root root 7 630 18:22 a.txt
926162 -rw-rw-r-- 2 root root 7 630 18:22 hardlink_a
  1. 使用ln -s a.txt symlink_a创建一个软链接,使用ls -li查看,可以看到软连接有自己的inode号,且不影响源文件的链接数,且文件大小也不一致:
1
2
3
4
5
(base) root@Server:~/test$ ls -li
总用量 8
926162 -rw-rw-r-- 2 root root 7 630 18:22 a.txt
926162 -rw-rw-r-- 2 root root 7 630 18:22 hardlink_a
926160 lrwxrwxrwx 1 root root 5 630 18:24 symlink_a -> a.txt
  1. 使用cat a.txtcat harlink_acat symlink_a会发现三者内容完全一致。现在修改a.txt中的内容为" 修改后的数据 ",然后查看三个文件的内容,三者内容同样一致。同样的,vim hardlink_avim symlink_a一样会修改同样的数据区,cat出来的内容也是相同的。
  2. 使用rm a.txt删除原文件,再使用cat指令打开两个链接文件,会发现软连接已经打不开了,而硬链接仍然可以打开。

  • 那么,软连接和硬链接的区别又在何处呢?

事实上,硬链接得到的文件会与原文件保持样的数据尺寸(但并不意味着复制了一份原数据)、一样的数据权限、一样的inode号,没有额外的区块和inode占用消耗,一定程度上可以防止区块数据和inode被意外释放;而软连接申请了新的inode,并占用了一定的区块数据(数据量取决于原文件名,如a.txt共五个字符,则占用5B),当原文件被删除,软连接也就无法打开了,这跟Windows中的表现是一致的。

(在Linux中,如果区块数据没有任何一个inode链接到,则可以认为这些区块已经被释放)


硬盘管理

认识硬盘

现代硬盘主要由柱头和碟片组成。为了高速的读写磁盘,人们设计了 MBR(Master Boor Record) ;随着硬盘容量的变大,2TB以上的硬盘采用 GPT(GUID partition table) 作为分区格式。这里主要介绍MBR。

Linux通过把硬件当成一个文件的方式管理硬盘,如计算机挂载的第一个机械硬盘的文件地址为:/dev/sda

在MBR格式中,我们将MBR称为主引导记录,用于引导系统的启动。如果你尝试在一个硬盘中建立一个多操作系统的软件目录,会经常接触到MBR的内容。MBR的大小为448字节,它和 分区表(partition table) 组成了第一个扇区,分区表的大小为64KB,即第一个扇区的大小为512KB。

  • 相对的,GPT第一个扇区有4K字节,因此能够引导更大的磁盘。

我们常说的分区,实际上只对分区表进行操作,同时只能记录划分为四组分区记录。但显然我们在Windows中常常用的硬盘分区多于4个区,这就要提到扩展分区逻辑分区了:

  • 主要分区与扩展分区由于MBR格式的限制,它们合起来[最多]只能有四个;
  • 扩展分区在Linux中只能存在一个,它指向主要分区之外的区域,在区域中存在扩展分区的分区表,该表不受64KB的限制,因此可以指向很多个逻辑分区,即所有的逻辑分区组成了扩展分区。

换句话说,受限于操作系统,以MBR格式为例,若一块硬盘设置了两个主分区,则一个硬盘的分区组成为:

MBR 448KB 分区表64KB
主分区1 主分区2 扩展分区
(原)主分区3 (原)主分区4
逻辑分区1 .......... 逻辑分区n

系统启动引导:BIOS与UEFI

对于常装机的朋友来说,BIOS与UEFI并不陌生。这里只简单介绍:

  • BIOS是写入固件程序,这里所说的固件指的是主板。因此BIOS是系统启动时第一个执行的程序,它会主动求搜寻MBR,然后按照引导信息去搜寻操作系统软件内容,最后启动我们所熟悉的操作系统。
  • UEFI使用C语言写成(相对的BIOS基本是由汇编写成),为了解决BIOS的一些缺点而提出;相对于写入固件的BIOS,它不需要第三方厂商支持就能部署,甚至在启动阶段就可以直接通过TCP/IP协议连上互联网,而不需要操作系统再次操作网卡硬件。某种意义上UEFI就是一个低级的操作系统。

硬盘状态查看

df指令可以查看磁盘的使用量,为了方便阅读,常使用【-h】指令以GB为单位显示数据,用【-T】列出文件系统:

1
2
3
4
5
6
7
8
9
10
11
(base) root@Server:~$ df -hT
文件系统 类型 容量 已用 可用 已用% 挂载点
udev devtmpfs 32G 0 32G 0% /dev
tmpfs tmpfs 6.3G 9.6M 6.3G 1% /run
/dev/nvme0n1p2 ext4 166G 27G 131G 17% /
tmpfs tmpfs 32G 62M 32G 1% /dev/shm
tmpfs tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs tmpfs 32G 0 32G 0% /sys/fs/cgroup
/dev/nvme0n1p1 vfat 511M 3.6M 508M 1% /boot/efi
/dev/sda ext4 2.7T 37G 2.6T 2% /data
tmpfs tmpfs 6.3G 64K 6.3G 1% /run/user/1000

硬盘分区、格式化、检验与挂载

① 分区与格式化

使用lsblk(list block device的缩写)命令可以查看磁盘及其分区的列表:

1
2
3
4
5
6
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda 8:0 0 2.7T 0 disk /data
nvme0n1 259:0 0 232.9G 0 disk
├─nvme0n1p1 259:1 0 512M 0 part /boot/efi
├─nvme0n1p2 259:2 0 168.5G 0 part /
└─nvme0n1p3 259:3 0 63.9G 0 part [SWAP]
  • 使用fdiskgdisk可以分别在MBR及GPT文件系统上进行分区。这些命令都比较简单,按照相应的提示步骤操作即可。(可以试使用fdisk -l来查看硬盘的文件系统)。>fdisk参考使用流程<
  • 使用mkfs.???指令进行格式化:如果我们想把硬盘格式化为ext4格式,则使用mkfs.ext4进行格式化操作,相应的还有mkfs.xfs等命令。如mkfs.ext4 /dev/sda

② 磁盘挂载与卸载

使用mount /dev/sda /data可以把设备/dev/sda挂载到/data目录下。
然而每次重新开机挂载信息就会丢失,所以我们需要把挂载信息写入/etc/fstab文件中:

  1. 首先,使用blkid命令查看硬盘的UUID。
  2. 使用vim /etc/fstab打开配置文件,在文末添加一行:
    <fs spec> <fs file> <fs vfstype> <fs mntops> <fs freq> <fs passno>,如UUID=06c17b55-521c-470d-aceb-69ab9be10e4b /data ext4 defaults 0 2,具体配置内容参考下表。
值名 值说明
fs spec 分区定位,可以给UUID或LABEL,例如:UUID=06c17b55-521c-470d-aceb-69ab9be10e4bLABEL=software
fs file 挂载点地址,如/data
fs vfstype 系统格式
fs mntops 挂载参数,详见下
fs freq 磁盘备份,默认为0,表示不需要dump操作
fs passno 磁盘检查顺序,填0时表示不检测。大于0时,1 是root文件系统保留位,之后的数字越大检查顺序越靠后
参数值 值说明
auto 系统自动挂载,fstab默认就是这个选项
defaults rw, suid, dev, exec, auto, nouser, and async.
noauto 开机不自动挂载
nouser 只有超级用户可以挂载
ro 按只读权限挂载
rw 按可读可写权限挂载
user 任何用户都可以挂载

请注意光驱和软驱只有在装有介质时才可以进行挂载,因此它必需填写noauto

  1. mount -a可以按/etc/fstab的配置挂载所有硬盘,一般也用来检测挂载配置的正确性。
  • 使用umount /dev/sda可以将各个挂载的设备卸载。