Linux的文件系统(5)——常用硬盘&文件系统相关的命令

简单的记录一些Linux系统下常用的与硬盘、文件系统相关的命令及第三方工具等

设备信息

查看硬盘分区状况

$ fdisk -l

列出系统上所有可用块设备信息(设备分区、大小、类型、挂载点等)

# 列出本系统下的所有硬盘与硬盘内的分区信息
$ lsblk
# 仅列出 /dev/vda 设备内的所有数据的完整文件名
$ lsblk -ifp /dev/vda

列出系统上所有可用块设备管理方式及UUID(设备分区、UUID、文件系统等)

$ blkid

查看已经被挂载的设备信息(设备分区、已使用空间、可用空间、挂在点等)

$ df -h

通过 /proc/devices 文件查看系统识别的设备(字符设备、块设备)

$ cat /proc/devices

网络设备是特殊的设备文件,它并不存在于 /dev/ 下面。网络设备是一个 net_device 结构,并通过 register_netdev 注册到系统里,可以通过 ifconfig 命令查看

$ ifconfig -a

通过 /proc/partitions 文件查看系统识别的分区(分区名称、大小等)

$ cat /proc/partitions

查看某一硬盘的具体信息(厂商、容量、分区表格式等)

$ parted /dev/vda print

Model: Virtio Block Device (virtblk) # 磁盘的模块名称(厂商)
Disk /dev/vda: 42.9GB # 磁盘的总容量
Sector size (logical/physical): 512B/512B # 磁盘的每个逻辑/物理扇区容量
Partition Table: gpt # 分区表的格式 (MBR/GPT)
Disk Flags: pmbr_boot

Number Start End Size File system Name Flags # 下面才是分区数据
1 1049kB 3146kB 2097kB bios_grub
2 3146kB 1077MB 1074MB xfs
3 1077MB 33.3GB 32.2GB lvm

通过查看对应硬盘的 rotational 文件,判断是否为机械硬盘

$ cat /sys/block/sda/queue/rotational
如果输出是 1,磁盘是HDD。 如果输出是 0,磁盘是 SDD。 因为,SSD 不会旋转

使用 S.M.A.R.T. 工具监控硬盘信息

# CenOS下安装smartctl第三方包
$ sudo yum install smartmontools

# 使用smartctl查看硬盘信息
$ sudo smartctl -a /dev/sda
# 配合grep查看某一项信息
$ sudo smartctl -a /dev/sda | grep 'Rotation Rate'

使用 lshw 工具查看电脑硬件信息

# CentOS下安装lshw
$ sudo yum -y install lshw

# 列出计算机硬件信息
$ lshw
# 列出硬件概要信息
$ lshw -short
# 列出所有磁盘和存储控制器
$ lshw -class disk -class storage
# 列出处理器相关设备
$ lshw -class cpu
# 列出内存相关设备
$ lshw -class memory

查看计算机开机信息:kernel 会将开机信息存储在 ring buffer 中。您若是开机时来不及查看信息,可利用 dmesg 来查看。开机信息亦保存在 /var/log 目录中,名称为 dmesg 的文件里

# 一般配合less或grep使用,如下命令可查看开机信息中的硬盘信息
$ dmesg | grep -i -e scsi -e ata

列出连接到USB总线的所有设备

$ lsusb

列出更详细的USB设备信息

$ usb-devices

查看CPU信息

$ cat /proc/cpuinfo

查看内存和 swap 分区的使用情况的

$ free
total used free shared buffers cached
Mem: 1030796 130792 900004 0 15292 55420
-/+ buffers/cache: 60080 970716
Swap: 2047992 0 2047992

内存信息中buffers和cache的区别: 简单来讲,cached 是给读取数据时加速的,buffers 是给写入数据加速的。cached 是指把读取出来的数据保存在内存中,当再次读取时,不用读取硬盘而直接从内存中读取,加速了数据的读取过程;buffers 是指在写入数据时,先把分散的写入操作保存到内存中,当达到一定程度后再集中写入硬盘,减少了磁盘碎片和硬盘的反复寻道,加速了数据的写入过程

硬盘挂载

分区

MBR设备使用 fdisk 命令

$ fdisk /dev/hda

GPT设备使用 gdisk 命令

$ gdisk /dev/sda

新分区某块硬盘后,通过 partprobe 更新Linux核心的分区表信息

$ partprobe -s # -s 参数是用于将返回信息输出到屏幕终端

GNU组织也开发了另一款功能强大的分区工具:parted,可以用于分区(MBR/GPT通用)

# 首先类似fdisk一样,先选择要分区的硬盘
$ parted /dev/sda
# 接下来可以选择分区表,默认msdos格式,使用gpt格式,输入gpt后回车
$ (parted) mklabel
gpt
# 执行mkpart命令,分别输入分区名称,文件系统和分区的起止位置
$ (parted) mkpart
# 可以多次执行mkpart进行多次分区
$ (parted) mkpart
# 分好区后可以使用print命令打印分区信息
$ (parted) print
# 如果某个分区错了,可以使用rm命令删除分区
$ (parted) rm 1 # rm后面使用分区的号码
# 也可以及时更改分区的小
$ (parted) resize
# parted下也可以直接对分区做格式化,但只能格式化成 ext2 文件系统
$ (parted) mkfs
# 由于parted内建的mkfs还不够完善,我们也可以使用quit命令退出parted,再使用mkfs命令对分区进行格式化
$ (parted) quit

要注意的是,parted 中所有的操作都是立即生效的,没有保存生效的概念。这一点和 fdisk 交互命令明显不同,所以做的所有操作要加倍小心

格式化

格式化其实就是将具体的硬盘分区“格”成某一文件系统。使用 mkfs 这个指令

# 将/dev/sda4分区格式化为xfs文件系统
$ mkfs.xfs /dev/sda4
# 通过agcount参数为xfs文件系统格式的读写数据流设置多线程
$ mkfs.xfs -f -d agcount=2 /dev/sda4 # -f参数为强制格式化

# 将/dev/sda5分区格式化为ext4格式
$ mkfs.ext4 /dev/sda5

可以查看目前mkfs命令支持的文件系统格式

$ mkfs[tab][tab]
mkfs mkfs.btrfs mkfs.cramfs mkfs.ext2 mkfs.ext3 mkfs.ext4
mkfs.fat mkfs.minix mkfs.msdos mkfs.vfat mkfs.xfs

可以使用 -t 参数查看某一文件系统格式的默认参数

$ mkfs -t xfs

文件系统的检查和修复

当硬盘上的文件系统出现问题,在没有被挂载,或已被卸载下来的时候,可以使用对应文件系统的修复工具尝试修复

# 针对xfs系统可使用xfs_repair
$ xfs_repair /dev/sda4
# 针对ext4可使用fsck.ext4
$ fsck.ext4 /dev/sda5

挂载

作为挂载点的目录理论上应该是空目录。如果挂载目录不是空目录,那么挂载了文件系统之后,原目录下的东西就会暂时隐藏。但并不会被覆盖,重现卸载后,原内容可恢复访问

依照fstab文件自动挂载硬盘

$ mount -a

手动挂载某一新的分区到对应目录

# 一定要先创建对应的空目录
$ mkdir -p /home/test
# 挂载
$ mount /dev/sda4 /home/test

现代Linux系统会自动识别挂载设备的文件系统,不过也可以通过-t命令指定具体的文件系统

$ mount -t xfs /dev/sda4 /home/test

也可以使用UUID来完成硬盘的挂载(UUID具有更好的唯一性,在某些情况下会特别有用)

# 查看对应设备文件的UUID
$ blkid /dev/sda4
/dev/sda4: UUID="e0a6af55-26e7-4cb7-a515-826a8bd29e90" TYPE="xfs"
# 使用UUID挂载
$ mount UUID="e0a6af55-26e7-4cb7-a515-826a8bd29e90" /home/test

mount命令也可以将某个目录挂载到另外一个目录去。这并不是挂载文件系统,而是额外挂载某个目录的方法! 虽然下面的方法也可以使用 symbolic link 来链接,不过在某些不支持符号链接的系统运行中,还是得要通过这样的方法才行

# 挂载
$ mount --bind /var /data/var
#使用ls命令查看两个目录信息
$ ls -lid /var /data/var
16777346 drwxr-xr-x. 22 root root 4096 Jun 15 23:43 /data/var
16777346 drwxr-xr-x. 22 root root 4096 Jun 15 23:43 /var
# 信息完全一样,因为挂载目录的原因

在某些特殊情况下,需要强制、重新挂载根目录

$ mount -o remount,rw,auto /

配置fstab文件实现开机自动挂载

一个简易的fstab文件内容如下(依然推荐使用UUID而不是设备文件名来标识设备)

# Device Mount point filesystem parameters dump fsck
#[设备/UUID] [挂载点] [文件系统] [参数] [dump] [fsck]
/dev/mapper/centos-root / xfs defaults 0 0
UUID=94ac5f77-cb8a-495e-a65b-2ef7442b837c /boot xfs defaults 0 0
/dev/sda2 /home xfs defaults 0 0
/dev/sda6 swap swap defaults 0 0
UUID=e0fa7252-b374-4a06-987a-3cb14f415488 /data/xfs xfs defaults 0 0

dump 参数是一个用于做备份的指令,现在基本不用了,写0就行。fsck 参数为是否使用 fsck 检验扇区,用以查看文件系统是否完整(clean),现在也基本不用了,写0就行

在fstab文件中必须手动指定每个设备的文件系统。同时,fstab文件修改后不会立即生效,可用 mount -a 重新强制读取fstab文件

卸载

使用umount命令完成卸载

# 查看已挂载的设备及对应文件系统
$ mount
# 卸载对应设备,可以通过设备名也可以用过挂载点为参数
$ umount /dev/sda4 # 通过设备文件名来卸载设备
$ umount /home/test # 通过挂载点来卸载准备

如果你就在当前设备节点内,是无法卸载当前设备的,可以跳到根目录去卸载设备

$ cd /home/test
$ umount /home/test
umount: /home/test: target is busy.
    (In some cases useful info about processes that use
     the device is found by lsof(8) or fuser(1))
$ cd /
$ umount /home/test

swap分区

建立swap分区第一步还是在先分区

$ fdisk /dev/sdb #还是以MBR分区表为例

第二步是格式化成 swap 格式,使用 mkswap 命令

$ mkswap /dev/sdb1

启动新增的 swap 分区

$ swapon /dev/sdb1

新增swap之后,原有的swap空间就会变大了,可以通过 free 命令查看

$ free -h

也可以使用 swapon 命令查看当前swap空间的状态

$ swapon --show

swap 分区可以随时取消

$ swapoff /dev/sdb1

使用 -a 参数关闭所有的 swap 分区

$ swapoff -a

swap 分区也可以通过 fstab 文件实现自动挂载

$ vim /etc/fstab
# 使用UUID配置swap分区的自动挂载
UUID=4021be19-2751-4dd2-98cc-383368c39edb swap swap defaults 0 0

使用文件的方式来建立 swap 分区

相比于使用一个物理分区作为交换空间,使用交换文件可以更方便地随时调整大小或者移除。当硬盘空间有限(例如常规大小的SSD)时,使用交换文件更加理想

自Linux内核版本5.0起,Btrfs文件系统支持交换文件,但有限制。有关更多信息,可见 Btrfs

使用 dd 去创建一个由你自己指定大小的交换文件

$ dd if=/dev/zero of=/swapfile bs=1M count=512 status=progress

为交换文件设置权限(交换文件全局可读是一个巨大的本地漏洞)

$ chmod 600 /swapfile

创建正确大小的文件后,将其格式化用来作为交换文件

$ chmod 600 /swapfile

启用交换文件作为swap空间

$ swapon /swapfile

交换值(Swappiness)

swappiness 参数代表了内核对于交换空间的喜好(或厌恶)程度。Swappiness 的值可以是 0 到 200 之间。设置这个参数为较低的值会减少内存的交换,从而提升一些系统上的响应度。较高值会导致内核尝试使用交换空间,而值100意味着各IO的喜好(或厌恶)程度相等

查看当前交换值(Swappiness)

$ sysctl vm.swappiness

临时设置交换值(Swappiness)

$ sysctl -w vm.swappiness=10

要永久设置交换值,请创建sysctl.d配置文件

$ vim /etc/sysctl.d/99-swappiness.conf
vm.swappiness=10

优先级

如果你有多个交换文件或交换分区,你应该考虑给它们各自分配一个优先级值(0 到 32767)。可以通过给性能较好的硬盘上的swap分区较高的优先级而改善swap的性能

在 fstab 中通过 pri 参数指定 swap 分区的优先级

/dev/sda1 none swap defaults,pri=100 0 0
/dev/sdb2 none swap defaults,pri=10 0 0

或者通过 swapon 的 --priority 参数指定优先级

$ swapon --priority 100 /dev/sda1

LVM技术

可用于LVM的分区需要使用‘8e’类型,所以我们在物理分区的时候就要设置分区类型

$ fdisk /dev/sdb
Command (m for help): n ## 新建
Command action
  e extended
  p primary partition (1-4)
p ## 主分区

Partition number (1-4): 1 ## 分区号
First cylinder (1-1044, default 1): ## 回车用默认的1
Last cylinder, +cylinders or +size{K,M,G} (1-1044, default 1044): +1G ## 大小

Command (m for help): t ## 改变类型
Selected partition 1
Hex code (type L to list codes): 8e ## LVM 的分区代码
Changed system type of partition 1 to 8e (Linux LVM)

物理卷准备工作:将对应分区作为LVM的物理卷

$ pvcreate /dev/sdb1

检查物理卷的准备情况

$ pvdisplay

可以随时移除当前物理卷

$ pvremove /dev/sdb1

创建逻辑卷组(这里使用三个物理卷分区创建了一个逻辑卷组)

$ vgcreate volume-group1 /dev/sdb1 /dev/sdb2 /dev/sdb3

检查逻辑卷组的准备情况

$ vgdisplay

删除逻辑卷组

$ vgremove volume-group1

创建逻辑卷(这里创建大小100M,名字为lv-name1的逻辑卷)

$ lvcreate -L 100M -n lv-name1 volume-group1

检查逻辑卷的准备情况

$ lvdisplay

现在逻辑卷已经准备好了,我们可以格式化和挂载逻辑卷,就与处理其他分区没有区别

# 格式化
$ mkfs.ext4 /dev/volume-group1/lv-name1
# 挂载
$ mkdir /lvm-mount
$ mount /dev/volume-group1/lv1 /lvm-mount/

删除逻辑卷前要先卸载

$ umount /lvm-mount/
$ lvremove /dev/volume-group1/lv-name1

扩展一个LVM卷

调整逻辑卷大小的功能是LVM最有用的功能。注意,调整逻辑卷大小之后,也需要对文件系统调整大小进行匹配。这个额外的步骤各不相同,取决于创建文件系统的类型

首先,还是要卸载掉已经挂载的逻辑卷

$ umount /lvm-mount/

然后,重新设置卷的大小

$ lvresize -L 200M /dev/volume-group1/lv-name1

接下来,检查磁盘错误(以ext4文件系统为例)

$ e2fsck -f /dev/volume-group1/lv-name1

扩展文件系统,更新文件系统信息(以ext4文件系统为例)

$ resize2fs /dev/volume-group1/lv-name1

检查现在逻辑卷的状态

$ lvdisplay

现在,这个逻辑卷可以重新挂载了

缩减一个LVM卷

缩减逻辑卷与扩展不同的地方就是要先缩小文件系统的大小,再缩小逻辑卷大小

首先,卸载卷

$ umount /dev/volume-group1/lv-name1

先缩小文件系统(以ext4文件系统为例)

$ resize2fs /dev/volume-group1/lv-name1 100M

减少逻辑卷大小

$ lvresize -L 100M /dev/volume-group1/lv-name1
# 这里会报一个警告:
WARNING: Reducing active logical volume to 100.00 MiB THIS MAY DESTROY YOUR DATA (filesystem etc.) Do you really want to reduce lv1? [y/n]: y Reducing logical volume lv1 to 100.00 MiB Logical volume lv1 successfully resized

检查现在逻辑卷的状态

$ lvdisplay

现在,这个逻辑卷又可以重新挂载了

扩展一个LVM卷组

如果我们有一个准备好的新的逻辑卷,也可以方便的扩展卷组

$ vgextend volume-group1 /dev/sdc1

创建设备文件

Linux下一切皆文件。设备文件也可以通过系统命令直接创造

# 创建一个设备代码 252, 10 的外接存储设备
$ mknod /dev/vda10 b 252 10 # 参数b表示此设备标记为外接存储设备

# 创建一个 FIFO 文件
$ mknod /tmp/testpipe p # 参数b表示此设备标记为FIFO文件

FIFO文件也可以使用 mkfifo 命令来创建

$ mkfifo /tmp/fifoname

文件系统相关

RHEL 7 之后的系统中,XFS代替了ext4成为了默认文件系统,这两种文件系统格式使用的相关命令及区别如下:

任务 ext4 XFS
创建文件系统 mkfs.ext4 mkfs.xfs
挂载文件系统 mount mount
查看文件系统的信息 dumpe2fs xfs_info
重新定义文件系统大小 resize2fs xfs_growfs
修复文件系统 e2fsck xfs_repair
在文件系统中更改标签 e2label xfs_admin -L
报告磁盘空间和文件使用情况 quota quota
调试文件系统 debugfs xfs_db
将关键文件系统元数据保存到文件中 e2image xfs_metadump

XFS 文件系统的大小不能直接缩小;xfs_growfs 命令仅用于增加大小

TRIM技术

从ext4文件系统开始到XFS文件系统,现代文件系统针对SSD可支持TRIM技术,即通过发送 discard 请求来通知存储器哪些 block 不再使用,来缓解SSD的写放大效应

可以通过 /sys/block 下的信息来判断某一 SSD 是否支持 TRIM,discard_granularity 非 0 表示支持

$ cat /sys/block/sda/queue/discard_granularity
0
$ cat /sys/block/nvme0n1/queue/discard_granularity
512

也可以使用 lsblk 命令来检测,DISC-GRAN (discard granularity) 和 DISC-MAX (discard max bytes) 列非 0 表示该 SSD 支持 TRIM 功能

$ lsblk --discard

/etc/fstab 文件中通过添加 discard 参数来来启用 TRIM,添加前请确认你的 SSD 支持 TRIM

/dev/sdb1 /data1 ext4 defaults,noatime,discard 0 0

util-linux 中自带了 fstrim 工具,可以自动检测硬盘是否支持 trim 功能,并在已挂载文件系统上执行 trim

$ fstrim -a -v

Intel Optane 系列 SSD 不同于 NAND, 使用了 write-in-place 技术, 没有垃圾回收,没有 trim。而 Intel P4500、P4600 系列的 NVMe SSD 都是 NAND 产品,主动 trim 可以优化性能并延长寿命,特别是写频繁场景

/dev/disk/by-*** 系列文件

/dev/disk/下,Linux 系统会根据 udev 的配置对系统识别的硬盘自动创建一系列的文件,其官方解释如下:

by-id - creates a unique name depending on the hardware serial number.
by-label - almost every file system type can have a label.
           All your volumes that have one are listed in the /dev/disk/by-label directory.
by-path - creates a unique name depending on the shortest physical path to the device
by-uuid - is a mechanism to give each filesystem a unique identifier.
           These identifiers are generated by the mkfs utilities.

查看软件/文件的路径

使用 whereis 命令

$ whereis nginx
nginx: /usr/sbin/nginx /usr/lib64/nginx /etc/nginx /usr/share/nginx /usr/share/man/man3/nginx.3pm.gz /usr/share/man/man8/nginx.8.gz

使用 find 命令

$ sudo find / -name python

使用 which 命令,查看当前所使用软件的版本路径

$ sudo which python

判断符号链接所指的具体文件

$ readlink -e /usr/bin/linkfile

查看系统 PATH 信息

$ echo $PATH

查看文件内容信息常用的命令

最常见的 cat

$ cat filename

使用 head 查看文件的开头部分,默认是开头10行

$ head -20 filename # 查看文件开头的20行

使用 tail 查看文件的结尾部分,默认是最后10行

$ tail -20 filename # 查看文件结尾的20行
$ tail -f filename # 实时动态查看最后10行,常用于跟踪日志文件等

使用 cut,用于显示每行从开头算起第 n1 到 n2 个字符

$ cut –c n1-n2 filename

统计指定文件的行数、字数和字节数

$ wc filename

查看当前文件夹下文件或设备所占空间大小

$ du -h

XFS文件系统有预分配机制,预分配的大小由参数 allocsize 确定。du 命令显示的文件大小包括该预分配的磁盘空间,可增加 --apparent-size 参数,查看实际文件的大小

$ du -sh filename --apparent-size

同时,du 命令默认递归查询当前文件夹及子文件夹下的所有文件,有时候内容过多且不必要,可使用 --max-depth 参数控制查询深度

$ du -h --max-depth=1

查看文件的inode内容信息

$ stat filename

使用 file 命令查看某一文件的具体类型及信息

$ file filename

使用 touch 命令更新文件的 atime、mtime、ctime 信息为当前时间,如果文件不存在 touch 命令将创建新文件

$ touch filename
# 使用 -d 参数可手动设置时间信息
$ touch -d '5 February 2022 5:02' filename
# 也可以使用 -t 命令,格式略有不同
$ touch -t 2006151230.30 filename

使用 diff 命令以逐行的方式,比较文本文件的异同处。如果指定要比较目录,则 diff 会比较目录中相同文件名的文件,但不会比较其中子目录

$ diff log2014.log log2013.log -y -W 50
2013-01 2013-01
2013-02 2013-02
2014-03 | 2013-03
2013-04 2013-04
2013-05 2013-05
2013-06 2013-06
2013-07 2013-07
2013-07 | 2013-08
2013-09 2013-09
2013-10 2013-10
2013-11 <
2013-12 <
# -y 表示并排格式输出,-W 50表示显示列宽为50
# | 表示前后2个文件内容有不同
# < 表示后面文件比前面文件少了1行内容
# > 表示后面文件比前面文件多了1行内容

其他

Linux 目前几乎支持所有的 Unix 类的文件系统,如 HFS、XFS、JFS、Minix fs等。Linux 也支持 NFS 文件系统。Linux 也支持 NTFS 和 vfat,但不支持 NTFS 的写操作。具体查看本机Linux 支持的文件系统,可查看下面的文件

$ ls -l /lib/modules/$(uname -r)/kernel/fs

查看系统目前已载入(注册)的文件系统则使用

$ cat /proc/filesystems

查看系统内核版本

$ uname -a

查看TTY如何被进程使用

#先用tty命令看看当前bash关联到了哪个tty
$ tty
/dev/pts/1

#看tty都被哪些进程打开了
$ lsof /dev/pts/1
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 907 dev 0u CHR 136,1 0t0 4 /dev/pts/1
bash 907 dev 1u CHR 136,1 0t0 4 /dev/pts/1
bash 907 dev 2u CHR 136,1 0t0 4 /dev/pts/1
bash 907 dev 255u CHR 136,1 0t0 4 /dev/pts/1
lsof 1118 dev 0u CHR 136,1 0t0 4 /dev/pts/1
lsof 1118 dev 1u CHR 136,1 0t0 4 /dev/pts/1
lsof 1118 dev 2u CHR 136,1 0t0 4 /dev/pts/1

#往tty里面直接写数据跟写标准输出是一样的效果
$ echo aaa > /dev/pts/2
aaa

查看设备驱动使用了哪些中断和每一类型的中断使用了多少次

$ cat /proc/interrupts
0: 727432 timer
1: 20534 keyboard
2: 0 cascade
3: 79691 + serial
4: 28258 + serial
5: 1 sound blaster
11: 20868 + aic7xxx
13: 1 math error
14: 247 + ide0
15: 170 + ide1

查看dma_chan数据结构向量表,Linux用以跟踪DMA通道的使用

$ cat /proc/dma

查看当前shell下的资源限定

$ ulimit -a

参考&扩展

Linux swap分区及作用详解 Linux中的swap交换空间详解 Configure disks to meet performance requirements Linux 下启用 SSD TRIM 功能 How to properly activate TRIM for your SSD on Linux: fstrim, lvm and dm-crypt Top-level Files within the proc File System List USB Devices Linux understanding /dev/disk/by- folders