鸟哥的Linux私房菜基础篇-第三版 人民邮电出版社

关系

Unix与Linux的关系

Linux 是一个类似 Unix 的操作系统,Unix 要早于 Linux,Linux 的初衷就是要替代 UNIX,并在功能和用户体验上进行优化,所以 Linux 模仿了 UNIX(但并没有抄袭 UNIX 的源码),使得 Linux 在外观和交互上与 UNIX 非常类似。

Linux、GNU、发行版的关系

打个比方操作系统就是一辆汽车。Linux是做汽车发动机的,也只生产发动机。有一家叫GNU的汽车零配件厂商,提供生产一整辆汽车的所有主要配件,只是它提供的发动机很差。各种发行版就是不同的汽车组装厂,它们自己不生主要的汽车配件,都是用GNU提供的配件——但发动机除外,发动机用的是Linux提供的。当然也有用其它发动机的,例如FreeBSD内核(kFreeBSD)。

GNU要求这些汽车组装厂,如果你除了内核以外其它配件基本都是用我生产的配件,你的名字中就应该带上我的标识。因此一些听话的厂商,例如Debian组装出来的用Linux发动机的汽车,就叫Debian GNU/Linux。事实上也有用FreeBSD发动机组装出来的Debian GNU/kFreeBSD——不过仅仅是6.0/7.0这两个版本提供过非官方的技术预览版,8.0开始就没再提供了。

当然,也有其它汽车厂商不用GNU的配件,自己生产配件自己组装汽车,但也用了Linux牌发动机的,例如安卓。根据GNU的这个命名方式,就应该叫Android/Linux。

GNU是一整个开源的操作系统,致力于以不含Unix代码的开源软件提供一个符合Unix标准的操作系统,所以GNU的全称是“GNU is Not Unix!”。

Linux的规则与安装

分时操作系统(Compatible Time-Sharing System,CTSS),可以让一台主机通过多个终端机(Terminal)连接进主机,利用主机的资源进行运算工作。

Linux的主要安装流程

  1. 调整启动媒体(BIOS)
  2. 选择安装结构与开机
  3. 选择语系数据
  4. 磁盘分区
  5. 引导装载程序、网络、时区设置与root密码
  6. 软件选择
  7. 安装后的首次设置

linux rescue救援模式

man page

代号 代表内容
1 用户在shell环境中可以操作的命令过可执行文件
5 配置文件或者是某些文件的格式
8 系统管理员可用的管理命令

忘记root密码

以单用户维护模式登录

1702301348428

各硬件设备在Linux中的文件名

设备 设备在Linux中的文件名
IDE硬盘 /dev/hd[a-d]
SCSI/SATA/USB硬盘 /dev/sd[a-d]
U盘 与SATA相同
软驱 /dev/fd[0-1]
打印机 25针:/dev/lp[0-2]
USB: /dev/usb/lp[0-15]
鼠标 /dev/usb/mouse[0-15]
PS2: /dev/psaux
当前鼠标 /dev/mouse
磁带机 /dev/ht0
/dev/st0
CD ROM/DVD ROM /dev/cdrom

磁盘

Linux根据内核检测到的磁盘设备顺序进行命名

image-20231223202023558

磁盘的第一个扇区记录了两个重要的信息:

  • 主引导分区(MBR):可以安装引导加载程序的地方,由446bytes
  • 分区表(partition table):记录整块硬盘分区的状态,有64bytes

所谓的分区只是针对那个64bytes的分区表进行设置

磁盘默认的分区表只能写入四组分区信息

这四组分区信息称为主(Primary)或扩展分区

分区的最小单位为柱面(cylinder)

image-20231223202125749

扩展分区的目的是使用额外的扇区来记录分区信息,扩展分区本身不能被拿来格式化

由扩展分区继续切出来的分区称为逻辑分区

  • 主分区与扩展分区最多只能有四个
  • 扩展分区最多只能有一个(操作系统的限制)
  • 逻辑分区是由扩展分区的持续切割出来的分区
  • 能被格式化后作为数据访问的分区分为主分区与逻辑分区
  • 在Linux中,IDE硬盘最多有59个逻辑分区(5号到63号,也就是/dev/hda5-63),SATA有11个

如果扩展分区被破坏,所有逻辑分区将会被删除,因为逻辑分区的信息都记录在扩展分区里

文件系统类型:

  • ext2/ext3:是Linux使用的文件系统类型。因为ext3文件系统多了日志的记录,对于系统的恢复比较快速,建议使用
  • physical volume(LVM):用来弹性调整文件系统大小的一种机制,可以让文件系统的大小改变而不改变原有的文件数据的内容
  • software RAID:利用软件仿真出磁盘阵列
  • swap:内存交换空间。由于swap并不会使用到目录树的挂载,所以swap不需要指定挂载点
  • vfat:同时被Linux和Windows支持的文件系统类型。

swap内存交换空间的功能:当有数据被存放在物理内存里面,但是这些数据又不是常被CPU所取用时,这些不常被使用的程序将会被放入硬盘的内存交换空间中,而将速度较快的物理内存空间释放出来给真正需要的程序使用。

系统启动过程

计算机的开机流程

  • BIOS:开机主动执行的韧体(写入到硬件上的一个软件程序),会认识第一个可开机的设备

  • MBR:第一个可开机设备的第一个扇区内的主引导分区快,内包含引导加载程序

  • Boot loader(引导加载程序):一只可读取内核文件来执行的软件

  • 内核文件:开始操作系统的功能

  • 每个分区都拥有自己的启动扇区

  • 实际可开机的内核文件是放置到各分区内的

  • loader可以直接指向或者是间接将管理权交给另一个管理程序

  • 内核的引导。

  • 运行 init。

  • 系统初始化。

  • 建立终端 。

  • 用户登录系统。

整个启动流程图

img

1.内核的引导

打开电源后,首先进入BIOS开机自检,按照BIOS中设置的启动设备(通常为硬盘)来启动。

操作系统接管硬件后,首先读入/boot目录中的内核文件。

2.运行init

init 进程是系统所有进程的起点

没有这个进程,其他进程不能启动。

init 程序首先是需要读取配置文件 /etc/inittab

image-20231008232657460

3.运行级别

程序的开机启动,在Windows中叫做Service(服务),在Linux中叫做daemon(守护进程)

init的一大任务就是运行这些开机启动的程序。

Linux允许为不同的场合,分配不同的开机启动程序,这就叫做runlevel(运行级别)。

也就是说,启动时根据"运行级别",确定要运行哪些程序。

7个运行级别

  • 运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
  • 运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登录
  • 运行级别2:多用户状态(没有NFS)
  • 运行级别3:完全的多用户状态(有NFS),登录后进入控制台命令行模式
  • 运行级别4:系统未使用,保留
  • 运行级别5:X11控制台,登录后进入图形GUI模式
  • 运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动
init 6 # 让机器重启

4.系统初始化

si::sysinit:/etc/rc.d/rc.sysinit 它调用执行了/etc/rc.d/rc.sysinit,而rc.sysinit是一个bash shell的脚本

rc.sysinit是每一个运行级别都要首先运行的重要脚本。

它主要完成的工作有:激活交换分区,检查磁盘,加载硬件模块以及其它一些需要优先执行任务。

l5:5:wait:/etc/rc.d/rc 5

这一行表示以5为参数运行/etc/rc.d/rc/etc/rc.d/rc是一个Shell脚本,它接受5作为参数,去执行/etc/rc.d/rc5.d/目录下的所有的rc启动脚本,/etc/rc.d/rc5.d/目录中的这些启动脚本实际上都是一些连接文件,而不是真正的rc启动脚本,真正的rc启动脚本实际上都是放在/etc/rc.d/init.d/目录下。

而这些rc启动脚本有着类似的用法,它们一般能接受start、stop、restart、status等参数。

5.建立终端

rc执行完毕后,返回init。这时基本系统环境已经设置好了,各种守护进程也已经启动了。

init接下来会打开6个终端,以便用户登录系统。在inittab中的以下6行就是定义了6个终端:

tty(Teletypes),是Linux的终端

tty1-tty6文字界面登录,tty7图形界面登录

1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

2、3、4、5的运行级别中都将以respawn方式运行mingetty程序

mingetty程序能打开终端、设置模式。

同时它会显示一个文本登录界面,这个界面就是我们经常看到的登录界面,在这个登录界面中会提示用户输入用户名,而用户输入的用户将作为参数传给login程序来验证用户的身份。

action:表示对应登记项的process在一定条件下所要执行的动作。

具体动作有:

respawn:当process终止后马上启动一个新的

wait:当进入指定的runlevels后process才会启动一次,并且到离开这个runlevels终止

initdefault:设定默认的运行级别,即我们开机之后默认进入的运行级别,不能是0,6,你懂的

sysinit:系统初始化,只有系统开机或重新启动的时候,这个process才会被执行一次

powerwait:当init接收到电源失败信号的时候执行相应的process,并且如果init有进程在运行,会等待这个进程完成之后,再执行相应的process

powerfail:当init接收到电源失败信号的时候执行相应的process,并且如果init有进程在运行,不会等待这个进程完成,它会直接执行相应的process

powerokwait:电源已经故障,但是在等待执行对应操作的时候突然来电了就执行对应的process

powerfailnow:当电源故障并且init被通知UPS电源已经快耗尽执行相对应的process

ctrlaltdel:当用户按下ctrl+alt+del这个组合键的时候执行对应的process

boot:只有在引导过程中,才执行该进程,但不等待该进程的结束;当该进程死亡时,也不重新启动该进程

bootwait:只有在引导过程中,才执行该进程,并等待进程的结束;当该进程死亡时,也不重新启动该进程

off:如果process正在运行,那么就发出一个警告信号,等待20秒后,再通过杀死信号强行终止该process。如果process并不存在那么就忽略该登记项

once:启动相应的进程,但不等待该进程结束便继续处理/etc/inittab文件中的下一个登记项;当该进程死亡时,init也不重新启动该进程

process:表示启动哪个程序或脚本或执行哪个命令等

6.用户登录系统

三种登录方式

  • 命令行登录
  • ssh登录
  • 图形界面登录

Linux 的账号验证程序是 login,login 会接收 mingetty 传来的用户名作为用户名参数。

然后 login 会对用户名进行分析:如果用户名不是 root,且存在 /etc/nologin 文件,login 将输出 nologin 文件的内容,然后退出。

只有/etc/securetty中登记了的终端才允许 root 用户登录,如果不存在这个文件,则 root 用户可以在任何终端上登录。

/etc/usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。

Linux关机

正确的关机流程为:sync > shutdown > reboot > halt

sync 将数据由内存同步到硬盘中。

shutdown 关机指令,你可以man shutdown 来看一下帮助文档。例如你可以运行如下命令关机:

shutdown –h 10 ‘This server will shutdown after 10 mins’ 这个命令告诉大家,计算机将在10分钟后关机,并且会显示在登陆用户的当前屏幕中。

shutdown –h now 立马关机

shutdown –h 20:25 系统会在今天20:25关机

shutdown –h +10 十分钟后关机

shutdown –r now 系统立马重启

shutdown –r +10 系统十分钟后重启

reboot 就是重启,等同于 shutdown –r now

halt 关闭系统,等同于shutdown –h now 和 poweroff

关机命令:

shutdown -h now

poweroff

init 0

重启命令:

shutdown -r now

reboot

init 6

系统目录结构

Linux安装模式下,磁盘分区的选择

目录树结构(directory tree):整个目录树结构最重要的就是根目录”/“

文件系统与目录树的关系(挂载)

挂载是利用一个目录当成进入点,将磁盘分区的数据放置在该目录下。也就是说,进入该目录就可以读取该分区。

主机硬盘的规划:

  1. 最简单的分区法:仅分出根目录和内存交换空间(/&swap),然后预留一些磁盘空间
  2. 根据用途,将需要较大容量,读写频繁的目录与根目录区分开

Linux的文件权限与目录配置

  • chown (change owner) : 修改所属用户与组。
  • chmod (change mode) : 修改用户的权限。
  • chgrp(change group):修改文件所属组

-R:进行递归的持续更改,即连同子目录下的所有文件都更改

-rw-r--r--   1     root   root   1219     2月   5 2021    txcdn.sh

​ 文件权限 连接数 所有者 用户组 文件大小 最后修改日期 文件名

-rwxrwx---

文件类型:

  • [d]代表目录
  • [-]文件
  • [l]连接文件
  • [b]设备文件里面的可供存储的接口设备
  • [c]设备文件里的串行端口设备

第一组r(read可读)w(write可写)x(execute可执行):文件所有者的权限

第二组rwx:文件所属用户组的权限

最后一组:其他人对此文件的权限

数字类型改变文件权限:

r:4

w:2

x:1

-rwxrwx—:[4+2+1] [4+2+1] [0+0+0]即770

符号类型改变文件权限:

格式:chmod u(ser)/g(roup)/o(thers)/a(ll) +(加入)/-(除去)/=(设置) r/w/x 文件或目录
chmod a+w tesh.sh 

代表所有身份添加可写权限

目录与文件的权限意义

  • r(ead):可读取此文件的实际内容,如读取文本文件的文字内容
  • w(rite):可以编辑,新增或是修改文件的内容(但不含删除该文件)
  • e)x(ecute):该文件具有可以被系统执行的权限

要开放目录给任何人浏览,至少给予r和x的权限,但w权限不能随便赋予

权限对目录的重要性

  • r:表示具有读取目录结构列表的权限
  • w:具有更改目录结构列表的权限,如新建或删除文件或目录,重命名目录或文件、转移文件目录位置
  • x:用户能否进入该目录成为工作目录

Linux文件种类与扩展名

普通文件(regular file):

  • 纯文本文件(ASCII):最多的一种文件类型,可用cat读取
  • 二进制文件(binary):执行的命令就是binary file
  • 数据格式文件(data):有些程序在运行的过程中会读取某些特定格式的文件,那些特定格式的文件可以被称为数据文件

目录(directory)

链接文件(link):类似Windows系统下面的快捷方式

设备与设备文件(device)

  • 块(block)设备文件:就是一些存储数据,以提供系统随机访问的接口设备
  • 字符(character)设备文件:一些串行端口的接口设备,如键盘鼠标等
  • 套接字(sockets):既然被称为数据接口文件,这种类型的文件通常被用在网络上的数据连接。我们可以启动一个程序来监听客户端,而客户端就可以通过socket来进行数据的通信。通常在/var/run下
  • 管道(FIFO,pipe):为了解决多个程序访问同一个文件所造成的错误类型。FIFO为first-in-first-out,第一个属性为[p]

一个Linux文件能否被执行,与它的第一列的10个属性有关,和文件名无关。即只要具有x权限,文件就可以执行

但可以被执行和可以执行成功不同。比如一个.txt文件虽然具有x权限,但是它本身是无法执行的。

Linux文件长度限制:

使用默认的ext2/ext3文件系统时,针对文件的文件名长度限制:

  • 单一文件或目录的最大容许文件名为255字符
  • 包含完整路径名称与目录(/)的完整文件名为4096个字符

Linux目录配置

Linux目录标准配置:FHS(Filesystem Hierarchy Standard),其主要目的是为了希望用户可以了解到已安装的软件通常放在哪个目录下

FHS依据文件系统使用的频繁与是否允许用户随意改动,将目录定义成为四种交互作用的形态:

可分享的(shareable) 不可分享的(unshareable)
不变的(static) /usr /etc
/opt /boot
可变动的(variable) /var/mail /var/run
/var/spool/news /var/lock
  • 可分享的:可以分享给其它系统挂载使用的目录
  • 不可分享的:自己机器上的设备文件或者是与程序有关的socket文件
  • 不变的:有些数据是不会经常变动的,如函数库,文件说明文件等
  • 可变动的:经常改变的数据,如登录文件、新闻组等

FHS针对目录树架构仅仅定义出三层目录下面应该放置什么数据:

  • root根目录:与开机系统有关
  • /usr:(UNIX software resource):与软件安装/执行有关
  • /var(variable):与系统运行过程有关

根目录的意义与内容:

所有的目录由根目录衍生而出,同时根目录也与开机、还原、系统修复等操作有关

FHS定义根目录的子目录

  • /bin:放置了在单用户维护模式下还能够被操作的命令
  • /boot:放置开机会使用到的文件,包括Linux内核文件以及与开机所需配置文件等
  • /dev:任何设备与接口设备都是以文件形式存在于该目录下
  • /etc:系统主要的篇日志文件几乎都放置在这个目录

FHS建议不要放置可执行文件在这个目录中

  • /etc/init.d:所有服务的默认启动脚本都存放在这里
  • /etc/xinetd.d:super darmon管理的各项服务的配置文件目录
  • /etc/X11:于X Window有关的各种配置文件
  • /home:系统默认用户主文件夹。一般创建一个一般用户账号时,默认的用户主文件夹都会规范到这里
    • ~:代表目前这个用户的主文件夹
    • ~abc:代表用户abc 的主文件夹
  • /lib:放置开机时会使用的函数库,以及在/bin和/sbin下面的命令会调用的函数库
  • /media:放置可删除的设备
  • /mnt:需要挂载的设备
  • /opt:第三方软件放置目录
  • /root
  • /sbin:放置开机过程中所需要的,里面包括开机、修复、还原系统所需要的命令。
    至于某些服务器软件程序,一般放置在/usr/sbin。
    本机自行安装的软件所产生的系统执行文件,则放置在/usr/local/sbin
  • /srv:网络服务启动后,这些服务所需要取用的数据目录
  • /tmp:暂时放置文件的地方

其他重要的目录

  • /lost+found:使用标准ext2/ext3文件系统格式才会产生的目录,目的在于当文件系统发生错误时,将一些丢失的片段放置在这个目录下
  • /proc:该目录本身是一个虚拟文件系统,它放置的数据都在内存中,例如系统内核、进程(process)、外部设备的状态以及网络状态等,不占任何硬盘空间
  • /sys:于/proc相似,主要记录于内核相关的信息

/usr的意义与内容:

  1. /usr可以分享给局域网内的其他主机使用
  2. 该目录放置”UNIX操作系统软件资源“的目录
  3. 所有系统默认的软件(distriburion发布者提供的软件)

应放置的文件内容

  • /usr/X11R6:为X Window 系统重要数据所放置的目录
  • /usr/bin:绝大部分用户可使用的命令都放置在这里
  • /usr/include:C/C++等程序语言的头文件与包含文件放置处
  • /usr/lib:包含个应用软件的函数库、目标文件,以及不被一般用户惯用的执行文件或脚本
  • /usr/local:系统管理员在本机自行安装自己下载的软件,建议安装到此目录
  • /usr/sbin:非系统正常运行所需要的系统命令。
  • /usr/share:放置共享文件的地方
  • /usr/src:一般源码建议放置在这里,src由source的意思,至于内核源码放在/usr/src/linux

/var的意义与内容:

  1. 主要针对常态性变动的文件,包括缓存(cache)、登录文件(log)以及某些软件运行所产生的文件

应放置的文件内容:

  • /var/cache:应用程序本身运行产生的缓存
  • /var/lib:程序本身执行的过程中,需要使用到的数据文件放置的目录。例如MySQL的数据库放置在/var/lib/mysql
  • /var/lock:某些设备或是文件资源一次只能被一个应用程序所占用。例如刻录机正在刻录一块光盘,只能确保一个人在这块光盘上写入数据,所以当第一个人使用刻录机时该刻录机就会被上锁
  • /var/log:登录文件放置的目录。如/var/log/wtmp(记录登录者的信息)
  • /var/mail:放置个人电子邮件信箱的地方
  • /var/run:某些程序启动后,会将他们的PID放置在此
  • /var/spool:通常放置一些队列数据

目录树(directory tree)

特性:

  • 起始点为根目录’/,root‘
  • 每一个目录不只能使用本地端的文件系统,也可以使用网络上的文件系统。例如NFS (Network File System)服务器挂载某特定目录
  • 每一个文件在此目录树中的文件名时独一无二的

1702560741113

绝对路径与相对路径

  • 绝对路径(absolute):由根目录开始写起的文件名或目录名称
  • 相对路径(relative):相对于目前路径的文件名写法。
  • .:代表当前目录,也可以使用./表示
  • …:代表上一层目录,也可以用…/表示
  • -:代表前一个工作目录
  • ~:代表”目前用户身份“所在的主文件夹

Linux文件与目录管理

关于执行文件路径的变量:$PATH

  • 不同身份与用户默认的PATH不同,默认能够随意执行的命令也不同
  • PATH可以修改,一般用户可以通过修改PATH来执行某些位于/sbin或/usr/bin下的命令来查询
  • 使用绝对或相对历经直接执行某个命令的文件名来执行
  • 命令应该放在正确的目录下,执行才会方便

cp(复制)

-a:相当于pdr的意思

-p:连同文件的属性一起复制

-i:若目标文件已经存在,在覆盖时会先询问操作的进行

-r:递归持续复制

文件内容查阅

  • cat:从第一行开始显示文件内容
  • tac:从最后一行开始显示
  • nl:显示的时候顺便显示行号
  • more:一页一页地显示
  • less:与more类似,可以往前翻页
  • head:只看头几行
  • tail:只看结尾几行
  • od:以二进制方式读取内容

cat(concatenate):

-n:打印出行号,连同空白行也会有行号

-b:列出行号,仅仅针对非空白行

head:

-n:后面接数字,代表显示几行

三个时间的意义

  • modification time(mtime)
    当该文件的”内容数据“更改时,就会更新这个时间
    内容数据指的是文件的内容,而不是文件的属性或权限
  • status time(ctime)
    该文件的”状态(status)“改变。即权限与属性被更改,会更新这个时间
  • access time(atime)
    该文件的内容被取用时。即用cat读取文件时,就会更新这个时间。

文件与目录的默认权限与隐藏权限 umask、chattr、lsttr

文件默认权限umask:目前用户在新建文件或目录时候的权限默认值

root@orangepizero3:~# umask
0022
root@orangepizero3:~# umask -S
u=rwx,g=rx,o=rx

默认情况如下:

  • 用户创建文件时默认没有x权限,为666
  • 用户创建目录,由于x是与是否可以进入此目录有关,因此所有权限开放,为777

umask的分数指“该默认值需要减掉的权限”,第一个0即第一组是特殊权限用,第三个2代表group被拿走了w权限

假设目前的umask为003,请问该umask下,新建的文件与目录权限是什么?

答:umask代表others被拿走了w和x权限

新建的文件:(-rw-rw-rw-)- (---------wx) = -rw-rw-r–

新建的目录:(drwxrwxrwx) -(---------wx) = drwxrwxr–

文件隐藏属性chattr,lsattr(在Ext2/Ext3文件系统中使用)

  • chattr(设置文件的隐藏属性)

    chattr [+-=]参数 文件或目录名称

    a:文件只能增加数据,而不能删除也不能修改数据,只有root才可以设置

    i:可以让一个文件不能被删除、改名、设置连接也无法写入或添加数据

文件特殊权限:SUID,SGID,SBIT

  • SUID:代表当用户执行此二进制程序时,在执行过程中用户会暂时具有程序所有者的权限
  • SGID:代表用户在这个目录下面新建的文件用户组都会与该目录组名相同
  • SBIT:代表在该目录下用户创建的文件只有自己和root能够删除

linux 一文带你彻底搞懂特殊权限位suid,sgid,sticky_suid和sgid的作用分别是什么-CSDN博客

  • SetUID(4)

    • 可以绕过基础权限体系,可以修改没有权限的文件
    • 当s出现在x上时,代表具有SUID。例如-rwsx-xr-x
    • SUID权限仅对二进制程序有效,不能够用在shell script上
    • 执行者对于该程序需要具有x的可执行权限
    • 本权限仅在执行能否该程序的过程中有效
    • 执行者将具有该程序所有者的权限
    • 理解:/etc/shadow保存了所有用户的账号和密码,user用户是无法访问这个文件的,但是user用户可以通过“passwd”更改自己的密码
    • 由此可知:user对于/usr/bin/passwd具有x权限,但passwd的拥有者是root,user在执行passwd的过程中,会暂时获得root的权限。/etc/shadow可以被user所执行的passwd所修改
  • SetGID(2)

    • SGID可以针对文件或目录设置
    • 唯一区别是suid获得命令所属用户的身份和权限,而sgid是获得命令所属用户组的身份和权限
    • SGID对二进制程序有用
    • 程序执行者对于该程序来说,需要具备x的权限
    • 用户对于此目录具有r与x的权限时,该用户能够进入此目录
    • 用户在此目录下的有效用户组(effective group)将会变成该目录的用户组
    • 若用户在此目录下具有w权限,则用户所创建的新文件的用户组与此目录的用户组相同
    • 理解:locate命令通过读取/var/lib/mlocate/mlocate.db查询命令二进制文件位置,文件权限对其他用户来说是---按道理来说其他用户无法使用locate命令,事实上可以使用,原因是locate 被设置了sgid**
  • Sticky Bit(1)

    • 只针对目录有效

      SBIT对于目录的作用:

    • 当用户对于此目录具有w,x权限,即具有写入的权限

    • 当用户在该目录下创建文件或目录时,仅有自己与root才有权利删除该文件

命令与文件的查询

查看文件类型:file

脚本文件名的查询

which(寻找”执行文件“)

文件名的查找

  • whereis(寻找特定文件)
    find直接查找硬盘,查找时间长
    Linux系统会将系统内所有的文件都记录在一个数据库文件/var/lib/mlocate里面,whereis和locate从数据库文件里查找
  • locate

​ updatedb:根据/etc/updatedb.conf的设置区查找系统硬盘内的文件名,并更新/var/lib/mlocate内的数据库文件

​ 根据/var/lib/mlocate内的数据库记载,找出用户输入的关键字文件名

  • find

    -mtime n	代表在n天之前的”一天之内“被更改过的文件
    -mtime +n 列出在n天之前(不含n天本身)被更改过的文件名
    -mtime -n 列出在n天之内(含有n天本身)被更改过的文件名
    find / -mtime 0
    # 代表从现在开始到24小时之前
    find / -mtime 3
    # 3天前的24小时内
    • +4代表大于等于5天前的文件名
    • -4代表小于等于4天内的文件名
    • 4则代表4-5那一天的文件名
-perm mode	查找文件权限刚好等于mode的文件
-perm -mode 必须要全部包含mode的文件
-perm +mode 包含任意mode的权限
-exec -command:-exec -it后边可以再接其他的命令来处理查找结果

权限与命令间的关系

命令在什么样的权限下才能够执行:

  • 让用户**能够进入某目录成为”可工作目录”**的基本权限是什么

    • 可使用的命令:cd
    • 目录所需权限:用户对于这个目录至少需要具有x的权限
    • 额外需求:如果用户想要在这个目录内利用ls查阅文件名,则此用户还需要r的权限
  • 用户在某个目录读取一个文件的基本权限是什么

    • 可使用的命令:例如cat、more
    • 目录所需要权限:至少就有x权限
    • 文件所需权限:用户对文件至少具有r权限
  • 用户可以修改一个文件的基本权限

    • 可使用的命令:vim、nano
    • 目录所需权限:x
    • 文件所需权限:r、w
  • 创建一个文件的基本权限

    目录所需权限:w,x重点是w

  • 进入目录并执行该目录下的某个命令

    • 目录所需权限:x
    • 文件:x

Linux磁盘与文件系统管理

认识EXT2文件系统

因为每种操作系统发所设置的文件属性和权限不同,所以需要“格式化”

通常我们把一个可挂载的数据为一个文件系统而不是一个分区

Linux的正规文件系统为Ext2(Linux second extended file system)

文件系统如何运行:Linux操作系统会把数据放在不同的块中,如下

  • super block:记录此文件系统的整体信息,包括inode/block的总量、使用量、剩余量
  • inode:记录文件的属性,一个文件占用一个inode,同时记录此文件的数据所在的block号码
  • block:实际记录文件的内容,若文件太大时会占用多个block

索引式文件系统(indexed allocation)

image-20231219185344417

inode向下寻找对应的block

FAT格式

一般用于U盘(闪存)

这种文件格式没有inde存在,每个block号码都记录在前一个block中。这种文件系统没办法一口气就知道四个block号码,需要一个一个地将block读出后,才会知道下一个block在何处

碎片整理

需要碎片整理的原因就是block太过于离散,此时文件读取的性能就会变得很差。这个时候可以通过碎片整理将同一个文件所属的block汇合在一起,这样数据的读取会比较容易。FAT的文件系统需要经常碎片整理一下。

由于Ext2是索引式文件系统,基本上不太需要进行碎片整理的。但如果文件系统使用太久,经常删除、编辑、新增文件时,那么还是可能会造成文件数据太过于离散的问题。

inode

文件系统一开始就将inode与block规划好,除非重新格式化(或者利用resize2fs)等命令更改文件系统大小,否则inode与block固定后就不再变动

如果文件系统太大,inode与block放在一起不容易管理

所以Ext2文件系统在格式化的时候基本上是区分为**多个块组(block group)**的,每个块组都有独立的inode/block/superblock系统。

在整体的规划当中,文件系统最前面有一个启动扇区(boot sector),这个启动扇区可以安装引导装载程序。这样我们就可以将不同的boot loader安装到个别的文件系统最前端,而不用覆盖整块硬盘唯一的MBR,这样也能制作出多重引导的环境。

image-20231219185816632

每一块组的六个主要内容:

  • data block(数据块)

    用来放置文件的内容。在Ext2文件系统中所支持的block大小由1KB,2KB以及4KB三种而已。由于block大小的区别导致该文件系统能够支持的最大磁盘容量与单一文件容量并不相同。因为block大小而产生的Ext2文件系统限制如下表、

    image-20231219190408362

    • 原则上,block的大小与数量在格式化完就不能够再改变了(除非重新格式化)
    • 每个block内最多只能够放置一个文件的数据
    • 如果文件大于block的大小,则一个文件会占用多个block数量
    • 若小于,则该block的剩余空间就不能被使用了
    • 所以进行文件系统格式化前,需要想好文件系统预计使用的情况
  • inodetable(inode表格)

    • inode包含下列文件数据:
    • 该文件的访问模式(r/w/x)
    • 该文件的所有者与组(o/g)
    • 该文件的大小
    • 该文件创建或状态改变的时间(ctime)、最近一次的读取时间(atime)、最近修改时间(mtime)
    • 定义文件特性的标志(flag),如SetUID
    • 该文件真正内容的指向(pointer)
    • inode的特色:
    • 每个inode大小固定为128bytes
    • 每个文件仅仅会占用一个inode
    • 文件系统能够创建的文件数量于inode的数量有关
    • 系统读取文件时先找到inode,并分析inode所记录的权限与用户是否符合,若符合才能够开始实际读取block的内容
    • 为了让inode能记录更多的信息,系统经inode记录block号码的区域定义为12个直接、一个间接、一个双间接与一个三间接记录区
    • 所谓的间接就是再拿一个block来当作记录block号码的记录区,如果文件太大,就会使用间接的block来记录编号。如果文件持续长大,那么就会利用所谓的双间接。

    image-20231219203242788

  • Superblock(超级块)

    • Superblock是记录整个文件系统相关信息的地方
    • 主要记录的信息:
    • block与inode的总量
    • 未使用与已使用的inode/block数量
    • block与inode的大小(block为1K,2K,4K,inode为128bytes)
    • 文件系统的挂载时间、最近一次写入数据的时间、最近一次检验磁盘(fsck)的时间等文件系统的相关信息
    • 一个valid bit的数值,若文件系统已被挂载,则valid bit为0。若未被挂载,则valid bit为1
    • 文件系统的基本信息都写在这里
    • 每个block group可能都由superblock。但是我们也说一个文件系统应该仅有一个superblock,后续的block group中的superblock可以用作第一个block group内superblock的备份
  • File system Description(文件系统描述说明)

    • 可以描述每个block group开始与结束的block号码,以及说明每个区段分别介于哪一个block号码之间。可以使用dumpe2fs来查看
  • block bitmap(块对照表)

    • 从block bitmap中可以知道哪些block是空的
    • 如果要删除某些文件时,那么那些文件原本占用的block号码就要释放出来,此时在block bitmap当中相对应到该block号码的标志就得要修改称为“未使用中”
    [root@VM-4-12-centos ~]# dumpe2fs /dev/vda1
    dumpe2fs 1.42.9 (28-Dec-2013)
    Filesystem volume name: <none>
    Last mounted on: /
    Filesystem UUID: 4b499d76-769a-40a0-93dc-4a31a59add28
    Filesystem magic number: 0xEF53
    Filesystem revision #: 1 (dynamic)
    Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
    Filesystem flags: signed_directory_hash
    Default mount options: user_xattr acl #默认挂载的参数
    Filesystem state: clean #代表文件系统没有问题
    Errors behavior: Continue
    Filesystem OS type: Linux
    Inode count: 3276800 #inode的总数
    Block count: 13106939
    Reserved block count: 545205
    Free blocks: 4098 #还有多少block可用
    Free inodes: 2536065
    First block: 0
    Block size: 4096
    Fragment size: 4096
    Group descriptor size: 64
    Reserved GDT blocks: 1017
    Blocks per group: 32768
    Fragments per group: 32768
    Inodes per group: 8192
    Inode blocks per group: 512
    Flex block group size: 16
    Filesystem created: Thu Mar 7 14:38:36 2019
    Last mount time: Thu Nov 23 20:59:28 2023
    Last write time: Thu Nov 23 20:59:25 2023
    Mount count: 66
    Maximum mount count: -1
    Last checked: Thu Mar 7 14:38:36 2019
    Check interval: 0 (<none>)
    Lifetime writes: 1653 GB
    Reserved blocks uid: 0 (user root)
    Reserved blocks gid: 0 (group root)
    First inode: 11
    Inode size: 256
    Required extra isize: 28
    Desired extra isize: 28
    Journal inode: 8
    First orphan inode: 4077
    Default directory hash: half_md4
    Directory Hash Seed: 58cbc593-e8e9-4c19-9dcf-645326b54c80
    Journal backup: inode blocks
    Journal features: journal_incompat_revoke journal_64bit
    日志大小: 128M
    Journal length: 32768
    Journal sequence: 0x01d170a5
    Journal start: 21328


    Group 0: (Blocks 0-32767) [ITABLE_ZEROED]
    Checksum 0x2c51, unused inodes 0
    主 superblock at 0, Group descriptors at 1-7
    保留的GDT块位于 8-1024
    Block bitmap at 1025 (+1025), Inode bitmap at 1041 (+1041)
    Inode表位于 1057-1568 (+1057)
    20230 free blocks, 0 free inodes, 1011 directories
    可用块数: 11776-11903, 11959-13311, 13648-14005, 14016-14254, 14336-16062, 16087-16127, 16384-32767
    可用inode数:

    上部分是superblock,下部分是blockgroup

​ Group0所占用的block号码从0到32767,第0号里存放superblock

  • inode bitmap (inode对照表)

    与block bitmap类似,用来记录使用与未使用的inode号码

与目录树的关系

目录与文件在Ext2文件系统当中记录数据的方式

  • 目录

    新建目录时,Ext2会分配一个inode与至少一块block给该目录。

    inode记录该目录的相关权限与属性,并可以记录分配到的那块block号码

    block记录在这个目录下的文件名与该文件名占用的inode号码数据。

    使用ls -i查看目录内文件所占用的inode号码

    目录并不会只占用一个block,如果文件太多导致一个block无法容纳下所有文件名与inode对照表时,Linux会给予该目录多一个block来继续记录相关的数据

  • 文件

    • 新建文件时,ext2会分配一个inode与相对于该文件大小的block数量给该文件

    例如:我的一个block为4KB,新建一个100KB的文件时,Linux将分配一个inode与25个block来存储该文件。由于inode仅有12个直接指向,因此还要多一个block来作为块号码的记录

  • 目录树的读取

    目录树从根目录读起,因此系统通过挂载的信息可以找到挂载点的inode号码(通常一个文件系统的最顶层inode号码会由2号开始),此时就能够得到根目录的inode内容,并依据该inode读取根目录的block内的文件名数据,再一层一层地往下读到正确地文件名。

[root@www ~]# ll -di / /etc /etc/passwd
 2 drwxr-xr-x 23 root root 4096 Sep 22 12:09 /
1912545 drwxr-xr-x 105 root root 12288 Oct 14 04:02 /etc
1914888 -rw-r--r-- 1 root root 1945 Sep 29 02:21 /etc/passwd

image-20231219215456906

  • 文件系统大小与磁盘读取性能
    • 当一个文件系统规划的很大时,由于硬盘上面的数据经常变动,所以整个文件系统上面的文件通常无法连续到一起(block号码不会连续的意思),而是填入式地将数据填入没有被使用的block当中。如果文件写入的block真的分的很散,此时就会有所谓的文件数据离散问题发生
    • 数据离散时,磁头得在整个文件系统中来来回回地频繁读取。可以将整个文件系统内的数据全部复制出来,将该文件系统重新格式化后再将数据复制回去
    • 如果文件系统真的特别大,那么当一个文件分别记录在这个文件系统的最前面与最后面的block号码中,此时会造成硬盘的机械手臂移动幅度过大,也会造成数据读取性能低。而且磁头在搜寻整个文件系统中,也会花费比较多的时间。

Ext2/Ext3文件的访问与日志文件系统的功能

新增一个文件的系统的行为:

  • 先确定用户对于与添加文件的目录是否具有w与x权限,有的话才能添加
  • 根据inode bitmap找到没有使用的inode号码,并将新文件的权限/属性写入
  • 根据block bitmap找到没有使用中的block号码,并将实际的数据写入block中,并且更新inode的block指向数据
  • 将刚才写入的inode与block数据同步更新inode bitmap与block bitmap,并更新superblock的内容

一般把inode table与data block称为数据存放区域,至于其他例如super block、block bitmap与inode bitmap等区段就被称为meta data(中间数据)

数据的不一致(Inconsistent)状态

  • 当出现不明原因导致系统中断时,写入的数据仅有inode table和data block,最后一个同步更新中间数据的步骤并没有做完,此时meta data的内容与实际数据存放不一致

日志文件系统(Journaling file system) Ext3后的文件系统才加入

  • 为解决数据不一致状态,文件系统划分出专门的一个块用来记录写入或修订文件时的步骤
  • 预备:当系统写入文件时,会现在日志记录块中记录某个文件准备要写入的信息
  • 实际写入:开始写入文件的权限和数据,开始更新metea data
  • 结束:完成数据与meta data的更新后,在日志记录块当中完成该文件的记录

Ext3较于Ext2的优化

  • 可利用性高:可以让系统中止到快速重新复原而不是持续地让e2fsck执行长时间的修复
  • 数据完整性:Ext3的日志式条件可以避免数据损毁的可能
  • 速度:因为3的日志使硬盘磁头的移动能够更有效地进行

Linux文件系统的操作

Linux使用异步处理来解决编辑大文件频繁操作硬盘导致的低效率问题

当系统加载一个文件到内存后,如果文件未被改动,则内存区段的文件数据会被设置为clean。当内存中的文件数据被更改过,此时会被设置为Dirty。此时所有的操作还都在内存中执行,并没有写入到磁盘中。系统会不定时地将内存中设置为Dirty地数据写回磁盘,以保持磁盘与内存数据的一致性。

Linux文件系统与内存的关系

  • 系统会将常用的文件数据放置在主存储器的缓冲区,以加速文件系统的读写
  • Linux的物理内存最后都会被用光
  • 可以使用sync来强迫内存中设置为Dirty的文件回写到磁盘中
  • 正常关机时,关机命令会主动调用sync来将内存的数据回写入磁盘内
  • 不正常关机时,由于数据未回写到磁盘中,因此重新启动后会花费大量时间进行磁盘检验,甚至导致文件系统的损坏

挂载点(mount point)的意义

将文件系统与目录树结合的操作称为挂载

同一个文件系统的某个inode只会对应到一个文件内容而已(因此一个文件占用一个inode),因此可以通过判断inode号码来确认不同文件名是否为相同的文件

其他Linux支持的文件系统与VFS

  • 传统文件系统:ext2/minix/MS-DOS微软磁盘操作系统/FAT(用vfat模块)/iso9660(光盘)等
  • 日志文件系统:ext3/ReiserFS(适用于更小型文件)/Windows‘NTFS/IBM’sJFS/SGI’sXFS
  • 网络文件系统:NFS/SMBFS

Linux VFS

整个Linux的系统都是通过一个名为Virtual Filesystem Switch(虚拟文件系统VFS)的内核功能去读取文件系统的

查看目前系统已经加载到内存中支持的文件系统
cat /proc/filesystems

整个Linux认识的文件系统其实都是VFS在进行管理,用户并不需要知道每个分区上头的文件系统是什么,VFS会主动帮助我们做好读取的操作

image-20231222205613229

文件系统的简单操作

磁盘与目录的容量:df,du

  • df:列出文件系统的整体磁盘使用量
  • du:评估文件系统的磁盘使用量(常常用于评估目录所占容量)

df

-h:以易读的GB,MB,KB格式显示
-i:不用硬盘容量,而以inode的数量显示
-a:列出所有的文件系统

df的读取范围在Super block内

/dev/shm目录,其实是利用内存虚拟出来的磁盘空间

du

-s:列出总量,而不列出每个个别的目录占用容量
-S:不包括子目录下的总计

连接文件:ln

一种是类似Windows的快捷方式功能的文件,可以快速连接到目标文件或目录。另一种是通过inode连接来产生新文件名,而不是产生新文件

硬链接(hard link)
  • 每个文件都会占用一个inode,文件内容由inode的记录来指向
  • 想要读取该文件,必须要经过目录记录的文件名来指向到正确的inode号码才能读取
  • 文件名只与目录有关,文件内容与inode有关
  • hard link只是在某个目录下新建一条文件名连接到某inode号码的关联记录

image-20231222213320531

上图表示用户可以通过1或2的目录inode指定的block找到两个不同的文件名,而不管是用哪个文件名都可以指到real那个inode去读取最终数据。

这两个文件虽然文件名不同,但是他们的inode号码相同,其实是“一模一样”的文件

如果将任何一个文件名删除,其实inode与block都还是存在的。此时访问另外一个文件名也能读取到正确文件内容。不论用哪个文件名编辑,最终的结果都会写入到相同的inode与block中

hard link设置连接文件时,磁盘的空间与inode数目都不会改变。它只是在某个目录下的block中多写入了一个关联数据,不增加inode也不耗用block

限制

  • 不能跨文件系统
  • 不能连接到目录

就是在创建一个独立的文件,而这个文件会让数据的读取指向它连接的那个文件的文件名。相当于一种“快捷方式”

只是利用了文件来作为指向的操作。所以当源文件删除后,快捷方式自然会打不开

inode号码不同,这两个文件是完全独立存在的。而且连接文件的重要内容就是它会写上目标文件的文件名

image-20231222215243148

由symbolic link所创建的文件为一个独立的新的文件,所以会占用掉inode与block

软连接可以连接目录

ln

-s:如果不加任何参数就进行连接,那就是hard link,加-s就是sysbolic link

软连接改连接文件,源文件也会跟着变动。当软连接连接到目录时,删除目录会影响源目录。

关于目录的连接数量

当我们新建一个目录时,新的目录的连接数为2,而上层目录的连接数则会增加1.

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

磁盘分区:fdisk
-l:输出后面接的设备的所有分区内容
root@test:~# fdisk /dev/sda

Welcome to fdisk (util-linux 2.37.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

This disk is currently in use - repartitioning is probably a bad idea.
It's recommended to umount all file systems, and swapoff all swap
partitions on this disk.


Command (m for help): m

Help:

GPT
M enter protective/hybrid MBR

Generic
d delete a partition # 删除一个分区
F list free unpartitioned space
l list known partition types
n add a new partition # 新增分区
p print the partition table # 在屏幕显示
t change a partition type
v verify the partition table
i print information about a partition

Misc
m print this menu
x extra functionality (experts only)

Script
I load disk layout from sfdisk script file
O dump disk layout to sfdisk script file

Save & Exit
w write table to disk and exit # 将操作写入分区表
q quit without saving changes # 不存储离开

Create a new label
g create a new empty GPT partition table
G create a new empty SGI (IRIX) partition table
o create a new empty DOS partition table
s create a new empty Sun partition table
Command (m for help): p

Disk /dev/sda1: 465.76 GiB, 500105217024 bytes, 976768002 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x69205244


Device Boot Start End Sectors Size Id Type
/dev/sda1p1 218129509 1920119918 1701990410 811.6G 72 unknown
/dev/sda1p2 729050177 1273024900 543974724 259.4G 74 unknown
/dev/sda1p3 168653938 168653938 0 0B 65 Novell Netware 386
/dev/sda1p4 2692939776 2692991410 51635 25.2M 0 Empty

Partition table entries are not in disk order.
  • boot:是否为开机引导模块

  • Start,End:表示这个分区在哪个柱面号码之间,决定分区大小

  • Type:文件系统类型

删除磁盘分区

  1. fdisk目标磁盘
  2. p:查看分区信息
  3. d:删除指定分区
  4. w写入并离开,q直接离开,不保存操作

新增磁盘分区

Command (m for help): p
Disk /dev/sda1: 465.76 GiB, 500105217024 bytes, 976768002 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x69205244

Device Boot Start End Sectors Size Id Type
/dev/sda1p3 168653938 168653938 0 0B 65 Novell Netware 386 # Novell Netware 386是一种网络操作系统,不是文件系统

Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1,2,4, default 1): 5
Value out of range.
Partition number (1,2,4, default 1): 4
First sector (2048-976768001, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-168653937, default 168653937): +512M
# 方式一:直接输入扇区的号码,但是需要计算柱面/分区的大小。方式二:使用+XXM来输入分区的大小?
# 偏移量是指新分区相对于当前扇区的位置差异。每个扇区在硬盘中都有一个唯一的编号,偏移量就是用来指定在哪个扇区之后或之前创建新分区。

例如,如果当前扇的编号是1000,如果你选择偏移量为100个扇区,那么新分区将从扇区号1100开始创建。同样地,如果选择偏移量为-100个扇区,新分区将从扇区号900开始创建。

Created a new partition 4 of type 'Linux' and of size 512 MiB.

Command (m for help): p
Disk /dev/sda1: 465.76 GiB, 500105217024 bytes, 976768002 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x69205244

Device Boot Start End Sectors Size Id Type
/dev/sda1p3 168653938 168653938 0 0B 65 Novell Netware 386
/dev/sda1p4 2048 1050623 1048576 512M 83 Linux

Partition table entries are not in disk order.

SATA硬盘最多支持到15号的分区,IDE支持63号。所以不要让SATA磁盘的分区超过15号,否则即使有剩余的柱面容量,但还是无法继续分区

fdisk无法处理2T以上的磁盘分区,尤其在应用在磁盘阵列(RAID)时,可能需要用到parted

磁盘格式化:mkfs,mke2fs

mkfs

-t:可以接受文件系统格式,后面接文件格式,如ext3等

mke2fs

-b:可以设置每个block的大小
-i:多少容量给予一个inode
-c:检查磁盘错误。两次-c会检测读写
-L:后面可以接卷标名称
-j:mke2fs是Ext2,加上-j后会自动加入journal而称为ext3
磁盘检验:fsck,badblocks

fsck

-t:指定文件系统
-A:依据/etc/fstab依次扫描
-a:自动修复有问题的扇区
-y:与-a类似
-C:可以在检测的过程中显示进度

执行fsck时,被检查分区务必不可挂载到系统上,需要在卸载的状态

fsck检查后,有问题的数据会被放置到lost+found中

使用fsck其实是在调用e2fsck

badblocks

-s:屏幕列出进度
-v:可以在屏幕看进度
-w:使用写入的方式来测试
磁盘挂载与卸载:mount
  • 单一文件系统不应该被重复挂载在不同的挂载点(目录)中
  • 单一目录不应该重复挂载多个文件系统
  • 作为挂载点的目录理论上应该都是空目录,否则目录会暂时消失

mount

Linux可以通过分析super block搭配Linux的驱动程序去测试挂载,从而不需要-t就能自动挂载

系统根据下面两个文件判定那些文件类型需要进行挂载测试

  • /etc/filesystems:系统指定的测试挂载文件系统类型
  • /proc/filesystems:Linux系统已经加载的文件类型
  • Linux的文件系统的驱动程序写在/lib/moudules/$ (username -r) /kernel/fs/
mount -l
/dev/mmcblk0p1 on / type ext4 (rw,noatime,errors=remount-ro,commit=600) [opi_root]

表示/dev/mmcblkp1挂载到/,文件类型为ext4,且挂载为可读写rw,

挂载CD或DVD

mount -t iso9660 /dev/cdrom /mnt/cdrom

光驱一旦挂载后就无法退出光盘

格式化与挂载软盘

挂载U盘

因为挂载在Linux上,所以不能用NTFS文件系统

如果是需要安装驱动

mount -t vfat -iocharset=cp950 /dev/sda1 /mnt/flash
# vfat为同时被win和linux支持的文件系统,iocharset指定语系,中文系统为cp950

重新挂载根目录与不特定目录

如挂载参数需要改变,或者根目录出现只读状态。需要重新挂载根目录

一种方法是重新启动

或者执行命令

mount -o remount,rw,auto/

也可以使用mount将一个目录挂载到另外一个目录,这样不会挂载整块文件系统,而是额外挂载某个目录的方法。相当于软连接

mount --bind /home /mnt/home
# 这样进入/mnt/home就相当于进入/home目录

umount

如果出现

[root@www cdrom]# umount /media/cdrom
umount: /media/cdrom: device is busy

由于你现在正在该目录下,所以需要退出才能卸载

也可以使用Label name进行挂载

使用dumpe2fs查看卷标名称

然后mount -L ”卷标名“ 挂载点

优点:可以不用知道该文件系统所在的接口与磁盘文件名

磁盘参数的修改:mknod,e2label,tune2fs

mknod

Linux内核通过文件的major和minor数值来识别设备数据,也就是通过这两个值来认设备

image-20231226213357289

b:设置设备名称成为一个外部存储设备文件,如硬盘
c:设置为外部输入设备文件,如键盘
p:设置为一个FIFO文件
范例:/dev/hdc10设备代码为22,10,建立此设备
mknod /dev/hdc10 b 22 10

e2label

卷标在Windows里就是C/D盘的名称C/D

e2label可以用来修改卷标

e2label 设备名称 新的label名称

tune2fs

-l:类似dumpe2fs -h的功能
-j:将ext2转为ext3
-L:类似于e2label,可以改写label

hdparm

-T:测试暂存区cache的访问性能
-t:测试硬盘的实际访问性能

用来设置IDE硬盘的一些高级参数

对于SATA硬盘,最多用来测试性能

[root@VM-4-12-centos rpm]# hdparm -Tt /dev/vda1

/dev/vda1:
Timing cached reads: 15432 MB in 1.99 seconds = 7749.28 MB/sec
Timing buffered disk reads: 440 MB in 3.02 seconds = 145.49 MB/sec

设置开机挂载

开机挂载/etc/fstab与/etc/mtab

系统挂载的限制

  1. 根目录必须挂载,而且先于其他挂载点被挂载进来
  2. 其他挂载点必须为已经新建的目录,可以任意指定,但一定要遵守必须的系统目录结构原则
  3. 所有挂载点在同一时间内,只能挂载一次
  4. 所有分区在同一时间内只能挂载一次
  5. 若进行卸载,需要先将工作目录转移到挂载点及其子目录之外
[root@www ~]# cat /etc/fstab
# Device Mount point filesystem parameters dump fsck
LABEL=/1 / ext3 defaults 1 1
LABEL=/home /home ext3 defaults 1 2
LABEL=/boot /boot ext3 defaults 1 2
tmpfs /dev/shm tmpfs defaults 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
LABEL=SWAP-hdc5 swap swap defaults 0 0
# 上述特殊字体癿部分不实际磁盘有关!其他则是虚拝文件系统戒
# 不内存置换空间 (swap) 有关。
  • 第一列:磁盘设备文件名或该设备的label

    用dumpe2fs查询卷标名,填写卷标名使用”LABEL=…"的方法填写

    利用设备名称来挂载分区时,硬盘就不能随便插在任意的插槽了
    新增硬盘时要注意卷标名

  • 第二列:挂载点

  • 第三列:磁盘分区的文件系统

    需要手动写入文件系统类型

  • 第四列:文件系统参数

    image-20231226223239538

image-20231226223249008

  • 第五列:能否被dump备份命令作用

    0表示不要做dump备份,1表示每天进行dump操作,2表示其他不定日期的dump备份操作

    通常这个数值不是0就是1

  • 第六列:是否以fsck检验扇区

    开机过程中,系统会默认以fsck检验我们的文件系统是否完整,而某些文件系统不需要检验,如swap
    0表示不检验,1表示最早检验(一般根目录),2也是要检验,不过1先检验

/etc/fstab是开机时的配置文件,实际文件系统的挂载会记录在**/etc/mtab和/proc/mounts**中
每次改动文件系统的挂载时会同时更新这两个文件
如果/etc/fstab文件有误,导致无法开机成功,而进入到单用户模式,根目录只有readonly,从而无法修改/etc/fstab

使用如下

mount -n -o remount,rw /

特殊设备loop挂载(镜像文件不刻录就挂载使用)

  • 挂载光盘/DVD镜像文件

    mount -o loop /root/xxx.iso /mnt/dvd
  • 创建大型文件

    # 使用dd命令新建一个空的文件
    dd if=/dev/zero of=/home/loopdev bs=1M count=512
    # if是input file,输入文件,/dev/zero可以一直输入0
    # of是out file,将输出的0写入/home/loopdev中
    # bs是每个block大小
    # count是总共几个bs

    #dd就好像堆砖块一样 ,将512块,每块1M的砖块堆成一个大文件

    然后格式化

    mkfs -t ext3 /home/loopdev

    挂载

    mount -o loop /home/loopdev /media/cdrom

内存交换空间swap创建

当内存不足时,内存中暂不使用的程序和数据会被移动到swap中

使用物理分区构建swap

步骤

  1. 分区:fdisk,主要是修改system ID为82对应Linux swap,分完区后partprobe让内核更新分区
  2. 格式化:mkswap 设备文件名
  3. 使用:swapon 设备文件名
  4. 查看:free查看内存情况

使用文件构建swap

  1. 使用dd新建一个大文件

    dd if=/dev/zero of=/tmp/swap bs=1M count=128

​ 2.使用mkswap将/tmp/swap格式化为swap文件格式

​ 3.使用swapon来将/tmp/swap启动

​ 4.使用swapoff关闭swap

swap使用上的限制

  • 在内核2.4.10版本以后,单一swap已经没有2GB限制
  • 最多仅能创建32个swap
  • 目前64位最大内存寻址到64GB,因此swap总量最大也是仅能达到64GB

文件系统的特殊查看与操作

boot sector与super block的关系

可安装开机信息的boot sector(启动扇区)独立出来的,并非放置到superblock中

  • superblock的大小为1024bytes

  • superblock前面需要保留1024bytes下来,来让引导装载程序可以安装

  • block为1024bytes时,boot sector和superblock各会占用一个blcok,则整个文件系统图如下

    Group 0的superblock是由1号block开始的,0号block留给了boot sector

image-20240101212734158

  • block大于1024bytes时,那么superblock会在0号。
    但superbolck其实只有1024nytes,为了怕浪费空间,因此第一个block内就含有boot sector和superblock

image-20240101213459748

磁盘空间的浪费问题

一个block只能放置一个文件,因此太多的小文件将会浪费非常多的磁盘空间。并且整个文件系统中包括superblock、inode table与其他数据等,其实都会浪费磁盘空间(意思是有些磁盘空间没用来记录数据,而是被superblock这些东西占用了),所以当我们新建文件系统时,一挂载后就会立刻有很多空间被浪费掉了

当我们使用ll查询目录时,第一行的total代表该目录下的所有数据所占用的实际block数量×block大小的值

总用量 626780
0 -rw-r--r-- 1 root root 0 8月 2 20:27 --add-repo
4 drwxr-xr-x 3 root root 4096 6月 3 2023 bilibiliTool
4 drwxr-xr-x 3 root root 4096 6月 5 2023 bot
4 drwxr-xr-x 2 root root 4096 12月 30 23:39 cert
4 -rw-r--r-- 1 root root 1781 4月 8 2021 cosfs.sh
4 drwxr-xr-x 3 root root 4096 11月 10 07:50 ctf
4 -rw-r--r-- 1 root root 1237 1月 28 2021 dnspod.sh
4 drwxr-xr-x 6 root root 4096 8月 7 17:15 feishubot
4 drwxr-xr-x 6 root root 4096 11月 5 20:19 frp-all
4 drwxr-xr-x 3 root root 4096 12月 31 00:26 harbor
626716 -rw-r--r-- 1 root root 641749145 12月 30 12:50 harbor-offline-installer-v2.10.0.tgz
4 drwxr-xr-x 4 root root 4096 10月 17 20:45 helmetci-builder
4 drwxr-xr-x 2 root root 4096 10月 15 17:00 package
4 drwxr-xr-x 4 root root 4096 10月 23 16:57 print
4 drwxr-xr-x 2 root root 4096 7月 5 23:30 qndxx
4 drwxr-xr-x 3 root root 4096 9月 1 16:19 test-feishubot
4 -rw-r--r-- 1 root root 1219 2月 5 2021 txcdn.sh
4 drwxr-xr-x 12 root root 4096 11月 20 22:13 yolo

cosfs.sh虽然只有1781bytes,但它却占用了4个block,浪费掉了(4096-1781)bytes,所有的block汇总后为626780KB,但实际比这个小

利用GNU的parted进行分区行为

fdisk无法支持高于2TB以上的分区,因此需要parted来进行分区

parted [device] [command [option]]

command:
新增分区:mkpart [primary|logical|extended] [ext3|vfat] 开始 结束
分区表:print
删除分区:rm [partition]

文件与文件系统的压缩与打包

压缩的原理

其实文件里面有相当多的”空间“存在,并不是完全填满的,压缩技术可以将这些空间填满,以让整个文件占用的容量下降。

不过压缩过的文件是无法被操作系统使用的,因此需要解压缩

Linux常见的压缩命令

扩展名,方便对照解压缩

*.Z		compress程序压缩的文件
*.gz gzip
*.bz2 bzip2
*.tar tar打包的数据,没有被压缩过
*.tar.gz tar打包的文件,经过gzip的压缩
*.tar.bz2 tar打包的文件,经过bzip2的压缩

Compress

非常老的一款压缩命令,gzip已经可以解开它压缩的文件了

解压缩用uncompress

-r:可以连同目录下的文件一起压缩
-c:将压缩数据输出到屏幕
-v:显示压缩后文件信息和压缩过程文件名的变化

gzip,zcat

-c:将压缩数据输出到屏幕上
-d:解压缩
-t:检验压缩一致性,看文件是否有错
-v:显示源文件/压缩文件的压缩比
-#:压缩等级,-1最快,压缩比最差,-9最慢,压缩比最好,默认是-6

当使用gzip进行压缩时,原本的文件被压缩为.gz后,源文件就不存在

zcat man.canfig.gz
# man.config原本是文本文件,zcat可以直接显示man.config.gz解压缩后的文件内容

bzip2,bzcat

bzip2是为了取代gzip并提供更佳的压缩比

-c
-d:解压缩
-k:保留源文件
-z:压缩
-v:显示压缩比
-#

bzcat可以不解压缩就可以直接读取压缩文件的内容

打包命令:tar

打包是将多个文件或目录组合成一个文件,而压缩是对文件或目录进行算法压缩,以减小文件大小。

常用参数

tar [-j][-z] [cv] [-f 新建的文件名] filename 		#打包与压缩
tar [-j|-z] [tv] [-f 新键的文件名] # 查看文件名
tar [-j|-z] [xv] [-f 新建的文件名] [-C 目录] # 解压缩
-c:新建打包文件
-t:查看打包文件的内容有哪些文件名
-x:解打包或解压缩,可以搭配-C在特定目录解开
-c,-t,-x不可同时出现在一串命令行中
-j:通过bzip2的支持进行压缩/解压缩,此时文件名为*.tar.bz2
-z:通过gzip的支持进行压缩/解压缩,此时文件名为*.tar.gz
-v:将过程中正在处理的文件名显示出来
-f filename:-f后接需要处理的文件名
-C 目录:用在解压缩

-p:保留备份数据的原本权限与属性
-p:保留绝对路径,即允许备份数据中存在根目录
--exclude=FILE:不要将某个文件打包进去

最常用的:

  • 压缩:tar -zcv -f filename.tar.gz 要被压缩的文件或目录
  • 查询:tar -ztv -f filename.tar.gz
  • 解压缩:tar -zxv -f filename.tar.gz -C 要解压缩的目录

被压缩的文件都被去掉了根目录

[root@VM-4-12-centos ~]# tar -ztv -f harbor-offline-installer-v2.10.0.tgz 
-rw-r--r-- root/root 646285764 2023-12-14 14:39 harbor/harbor.v2.10.0.tar.gz
-rwxr-xr-x root/root 1882 2023-12-14 14:39 harbor/prepare
-rw-r--r-- root/root 11347 2023-12-14 14:39 harbor/LICENSE
-rwxr-xr-x root/root 1975 2023-12-14 14:39 harbor/install.sh
-rw-r--r-- root/root 3643 2023-12-14 14:39 harbor/common.sh
-rw-r--r-- root/root 13761 2023-12-14 14:39 harbor/harbor.yml.tmpl

主要是为了安全

如果压缩的是/etc/xxx,在/tmp下解压时,不带根目录解开,解压的文件名就会变成/tem/etc/xxx,如果带根目录,解压后就会是绝对路径,一定会覆盖原有的/etc/xxx

1.解开单个文件

tar -zxv -f harbor-offline-installer-v2.10.0.tgz harbor/install.sh

2.打包某个目录,但不含该目录下的某些文件

tar -jcv -f /root/test.tar.bz2 --exclude=/root/etc* \
> --exclude=/root/test.tar.bz2 /etc /root
# 打包/root和/etc但不含/root下以etc开头的文件和打包后的文件

3.仅备份某个时刻还要新的文件

--newer-mtime=

tarfile:直接打包文件的称呼

tarball:打包后且被压缩的称呼

特殊应用

cd /tmp
# 将/etc整个目录边打包,边在/tmp中解开
tar -cvf - /etc | tar -xvf -
# 输出文件(standard output)与输入文件(standed input)都为-,又有一个 | 存在
# 可以把 - 看作是内存中的一个设备(缓冲区)

完整备份工具:dump

简单操作

-S:仅列出后面的待备份数据需要多少磁盘空间才能够完成备份
-u:将这次dump的时间记录到/etc/dumpdates
-v:将dump的文件过程显示出来
-level:一共-0 到 -9十个等级
-j:加入bzip2压缩
-f:类似tar,后面接产生的文件
-W:列出在/etc/fstab里面的具有dump设置的分区是否有备份过

当第一次进行dump后,再进行第二次dump,可以指定不同的备份等级。假如指定等级为1,此时新备份的数据只会记录与第一次备份所有差异的文件而已

image-20240102210549773

虽然dump支持整个文件系统或者是单一目录,但是对于目录的支持比较不足。

  • 当待备份的数据为单一文件系统

    可以使用完整的dump功能,备份时可以使用挂载点或者是设备文件名

  • 带备份的数据只是目录,并非单一文件系统

    例如你想备份/home/123,但是该目录并非独立的文件系统

    此时备份的限制有

    1. 所有的备份数据都必须要在目录下
    2. 并且仅能使用level 0,即仅支持完整备份而已
    3. 不支持-u参数,即无法创建/etc/dumpdates这个level备份的时间记录文件

用dump备份完整的文件系统

1.找出需要备份的文件系统
2.测试如果要备份此文件系统需要多少容量
dump -S /dev/sda1
3.将完整备份的文件名记录成为/root/boot.dump/boot
dump -0u -f /root/boot.dump/boot
# level 0级别完整备份,将备份文件输出到/root/boot.dump下,命名为boot
4.可以查看系统自动新建的记录文件
cat /etc/dumpdates

用dump备份非文件系统,即单一目录

dump -0j -f /root/etc.dump.bz2 /etc
# 备份单一整个目录/etc,并压缩

restore

用来恢复.dump文件

restore -t [-f dumpfile] [-h]	# 查看dump文件
restore -C [-f dumpfile] [-D 挂载点] # 比较dump和实际文件
restore -r [-f dumpfile] # 还原整个文件系统

模式不混用,意思是参数不能写一起

-t:此模式查看dump起来的备份文件有什么重要的数据
-C:可以将dump内的数据拿出来跟实际的文件系统比较
最终会列出”在dump文件内有记录,且目前文件系统不一样“的文件
-i:进入互动模式,可以仅还原部分文件,用在dump目录时的还原
-r:将整个文件系统还原

仅还原部分文件可以使用restore的互动模式

光盘写入工具

mkisofs:新建镜像文件

-o:接要产生的镜像文件名
-r:通过Rock Ridge产生支持Unix/Linux的文件数据,可以记录较多的信息
-v:显示构建ISO文件的过程
-m file:排除某个文件不到iso中
-V vol:新建Volume
-graft-point:可以定义位于镜像文件中的目录

光盘的格式一般称为ISO9660,这种格式一般仅支持旧版的DOS文件名,即文件名只能以8.3(文件名8个字符,扩展名3个字符)的方式存在,-r后可以记录较多信息

默认情况下,所有要被加到镜像文件中的文件都会被放置到镜像文件中的根目录,想要更改的话可以使用-graft-point参数,例如:

镜像文件中的目录所在=实际Linux文件系统的目录所在

/linux/etc=/etc(将Linux中的/etc内的所有数据备份到镜像文件中的/linux/etc目录中)

范例

mkisofs -r -V 'Linux_file' -o /tmp/system.img \ -m /home/loopdev -graft-point /root=/root /home=/home # 等号左边是镜像中的目录,右边是实际目录
# 备份输出文件命名为system.img
# 排除/home/loopdev

cdrecord:光盘刻录工具

  1. 检测刻录机所在位置

    cdrecord -scanbus dev=ATA,ATA是一种接口类型

  2. 进行CD的刻录

    1. 先抹除光盘原有的内容

      cdrecord -v dev=ATA:1,1,0 blank=fast(ATA:1,1,0是刻录机的位置,blank为抹除可重复写入的CD/DVD-RW)

    2. 开始刻录

      cdrecord -v dev=ATA:1,1,0 fs=8m -dummy -data \ /temp/system.img(fs指定多少缓存器,一般为8M)

      DVD的为cdrecord -v dev=ATA:1,1,0 fs=8m -dummy -data -sao \ driveropts=burnfree /tmp/system.img

    3. 测试挂载

      mount -t ios9660 /dev/cdrom /mnt

其他常见的压缩与备份工具

dd

dd可以读取磁盘设备的内容(几乎是读取扇区),然后将整个设备备份成一个文件

# 使用dd命令新建一个空的文件
dd if=/dev/zero of=/home/loopdev bs=1M count=512
# if是input file,输入文件,/dev/zero可以一直输入0
# of是out file,将输出的0写入/home/loopdev中
# bs是每个block大小
# count是总共几个bs

#dd就好像堆砖块一样 ,将512块,每块1M的砖块堆成一个大文件
# 将/etc/passwd备份到/tmp/passwd.back当中
dd if=/etc/passwd of=/tmp/passwd.back
# 将磁盘的第一个扇区备份
dd if=/dev/hdc of=/tmp/mbr.back bs=512 count=1

tar可以用来备份关键数据,而dd则可以用来备份整块分区或整块磁盘

你可以通过dd if=/dev/sda of=/dev/sdb来构建两块一模一样的磁盘,因为dd可以将/dev/sda内的所有数据,包括MBR和分区表一起复制到/dev/sdb中

cpio

cpio可以备份任何东西,包括设备文件。不过它不会主动去找文件备份,需要配合类似find等可以找到文件名的命令来cpio需要备份的数据在哪里

备份:cpio -ovcB > [file]
还原:cpio -ivcdu < [file]
查看:cpio -ivct < [file]
备份参数:
-o:将数据copy到file
-B:让默认的blocks增加至5120bytes
还原参数:
-i:将数据从文件复制到系统中
-d:自动新建目录
-u:自动将新文件覆盖到旧文件
-t:配合-i参数,可以在查看以cpio新建的文件或设备的内容
-v:让存储的过程中文件名可以在屏幕显示
0c:一种较新的portable format方式存储

Vim程序编辑器

按键说明

一般模式可用的按钮说明

光标移动
[Crtl]+[f] / [Crtl]+[b]或[Page Down/Up] 屏幕向下(上)移动
0或[Home] 移动到这一行的最前面字符
$或[End] 移动到这一行的最后面的字符
G 移动到文件的最后一行
gg 移动到文件的第一行,相当于1G
N 向下移动n行
查找与替换
/word 向下查询word字符
?word 向上查询word
n 重复前一个查找的操作
:n1,n2s/word1/word2/gc 在n1行到n2行之间寻找word1并替换为word2,加c开启询问
删除、复制与粘贴
x 删除,相当于[Backspace]
nx 向后连续删除n个字符
dd 删除光标所在的整行
ndd 向下连续删除n行
dG 删除从光标所在到最后一行的所有数据
yy 复制光标所在的那一行
p,P p将已复制的数据在光标下一行粘贴,P在上一行粘贴
u 复原上一个操作
[Crtl]+r 重复上一个操作
一般模式切换到编辑模式的可用的按钮说明
a,A a从目前光标所在下一个字符插入,A为从光标所在行的最后一个字符插入
o,O o为目前所在光标的下一行处插入新的一行,O为上一行
r,R r只会替换光标所在的字符一次,R会一直替换光标所在的文字,直到[Esc]为止
一般模式切换到命令行模式的可用的按钮说明
ZZ 若文件没有变动,则不保存离开。如果变动,则保存离开
:[filename] 另存文件
:r[filename] 即将filename这个文件内容加到光标后面
:n1,n2 w [filename] 将n1到n2的内容保存为新的文件
:! command 暂时离开vi执行命令
:set nu 显示行号
:set nonu 取消行号

vim的保存文件、恢复与打开时的警告信息

当我们在使用vim编辑时,vim会在被编辑文件的目录下再新建一个名为.filename.swp的文件

用户对filename的操作会被记录在.filename.swp中,当vim意外中断时,可以通过这个swp文件恢复

vim的功能

块选择(Visual Block)

image-20240105232110137

v 字符选择,会将光标经过的地方反白选择
V 行选择
[Ctrl]+v 块选择
y 反白部分复制
d 反白部分删除

多文件编辑

按钮
:n 编辑下一个文件
:N 编辑上一个文件
:files 列出目前这个vim的打开的所有文件

多窗口功能

:sp{filename}窗口切割

使用[Ctrl]+w+上箭头可以切换窗口

vim环境设置与记录:/.vimrc,/.viminfo

vim会将你曾经做过的行为记录在./.viminfo

image-20240105234840281

image-20240105234857741

vim常用命令简图

image-20240105234959424

其他vim使用注意事项

中文编码问题

  1. Linux默认支持的语系:与/etc/sysconfig/i8n有关
  2. bash的语系:与LANG变量有关
  3. 文件的原本编码
  4. 打开终端机的软件,如GNOME

最重要的是第三点与第四点

LANG=zh_CN.utf-8

语系编码转换

iconv -f 原本编码 -t 新编码 filename [-o newfile]

认识和学习bash

操作系统的内核(kernel)管理整个计算机硬件,而内核是需要被保护的,所以一般用户只能通过shell来跟内核进行通信

认识bash

硬件、内核与shell

我们必须通过shell将我们输入的命令与内核通信,好让内核可以控制硬件正确无误地工作

image-20240106234320111

image-20240106234948535

用户可以通过应用程序来指挥内核,让内核达到我们需要的硬件任务。因为应用程序其实在整个操作系统的最外层,像鸡蛋壳一样,所以叫做shell

也就是说,只要能够操作应用程序的接口都能够称为shell

狭义的shell指的是命令行方面的软件,广义的shell则包括图形界面的软件

系统的合法shell与/etc/shells功能

早年Unix使用的shell种类很多,有Bourne SHell(sh)、Sun的C SHell,商业上常用的K SHell

Linux使用的版本叫做“Bourne Again SHell(简称bash)”,它是sh的升级版,基于GNU架构下发展出来的

系统某些服务在运行过程中,会检查用户能够使用的shell,而这些shell的查询就是借助/etc/shells

bash shell的功能

  1. 命令记忆功能(history)

    通过上下键查询,记录在~/.bash_history中(前一次登录以前所执行过的命令)

  2. 命令与文件补全功能([Tab])

  3. 命令别名(alias)

  4. 作业控制、前台、后台控制

  5. 程序脚本(shell script)

  6. 通配符

bash shell的内置命令:type

可以通过type命令知道该命令是否来自于外部(非bash提供的命令)

为什么cd是内置命令,而常用的ls不是内置的?

ChatGPT:

cdbash的内置命令,而不是一个独立的可执行文件,因为它的功能是改变当前工作目录,这涉及到修改bash的运行环境。

  1. 修改当前工目录:cd命令的作用是改变bash的运行环境,将当前目录更改为指定的目录。这个操作需要直接访问和修改bash的内部状态,而不是简单地执行一个独立程序。

  2. . 跨进程:cd命令是用于改变bash的当前工作目录,这个状态是在进程级别上的。如果cd是一个独立的可执行文件,它只会在执行该可执行文件的子程中更改目录,而不会影响到父进程或其他进程。但是,由于cdbash的内置命令,它可以直接修改bash的当前工作目录,使得这个状态在整个bash会话中生效。

  3. 快速执行:作为内置命令,cd命令可以直接由bash解释器执行,而不需要启动一个新的进程来执行可执行文件。这样可以提高执行cd命令的速和效率。

  4. 与环境变量的交互:cd命令不仅可以改变当前目录,还可以与环境变量进行交互,如CDPATH环境变量。这种交互需要直接访问和修改bash的内部环境,因此将cd作为内置命令更加方便。

    综上所述,cd作为bash的内置命令,可以更方便、快速地修改bash的当前工作目录,与bash的内部环境进行交互,并在整个bash`会话中生效。

    待理解:(涉及操作系统的底层)

image-20240107225155215

shell的变量功能

什么是变量?

简单地说就是让某一个特定字符串代表不固定的内容。我们可以用一个简单的“字眼”来替代另一个比较复杂或者容易变动的数据。

变量就是以一组文字或符号等,来替代一些设置或者是一串保留的数据

  • 变量的可变性与方便性

    image-20240107230255157

​ 不同用户取得的变量名都叫MAIL,但每个MAIL对应的值不一样

  • 影响bash环境操作的变量

    某些特定变量会影响到bash的环境,例如PATH、HOME、MAIL等

  • 脚本程序的帮手

    image-20240107231731347

变量的显示与设置:echo,unset

在变量显示之前,变量的前面必须加上字符“$”

  • 变量的显示echo

    echo $PATH
    echo ${PATH}
    # 两种方式都可以

    # 变量的修改
    echo $myname

    myname=yourname
    echo $myname
    yourname
  • 变量的设置规则

    1. 变量与变量内容以一个等号连接

    2. 等号两边不能接空格符。myname=hello world也是错误的

    3. 变量名称只能是英文字母与数字,但是开头字符不能是数字

    4. 变量内容如果有空格,则使用双引号或单引号将变量内容结合起来

      双引号可以保持变量的内容,但单引号仅能是一般字符,不会有特殊符号

      • 双引号内的特殊字符如$等,可以保持原本的特性

        如果var="lang is $LANG",则echo $var可得lang is en_US

      • 单引号内特殊字符则仅为一般字符(纯文本)

        ar='lang is $LANG',则echo $var可得lang is $LANG

    5. 可用转义字符"\"将特殊符号(如回车键、$,\、空格符、!等)变成一般字符

    6. 在一串命令中,还需要通过其他的命令提供的信息,可以使用反单引号**`命令`或$(命令)**

      version=$(uname -r)后再echo $version

      在一串命令中,反单引号的命令会首先被执行

      cd /lib/modules/`uname -r`/kernel
      # 先执行uname -r,再执行cd
    7. 如果该变量增加了变量内容时,则可用**$变量名称${变量}**来累加内容

      PATH="$PATH":/home/bin

    8. 若该变量需要在其他子进程执行,则需要以export来使变量变成环境变量

      export PATH

    9. 通常大写字符为系统默认变量,自行设置的变量可以使用小写字符

    10. 取消变量的方法是通过unset 变量名称

什么是子进程?在目前的shell下,去打开另一个新的shell,新的shell就是子进程

在一般状态下,父进程的自定义变量是无法在子进程内使用,通过export可以让变量成为环境变量。

环境变量的功能

使用env查看环境变量与常见环境变量说明

  • HOME

    代表用户的主文件夹。cd~就是使用了这个变量

  • SHELL

    告知我们目前这个环境使用的shell是哪个程序

  • HISTSIZE

    与历史命令有关。即我们曾经执行过的命令可以被系统记录下来,而记录的条数则与这个变量有关

  • MAIL

    当我们使用mail命令在收信时系统会去读取的邮件信箱文件(mailbox)

  • PATH

    就是执行文件查找的路径,目录与目录之间以冒号分隔

  • LANG

    语系数据。一般来说中文编码zh_CN.gb2312或zh_CN

  • RANDOM

    随机数变量。一般系统会给出0-32767之间的数值

    # 使用0-9之间的数值,利用declare -i number=$RANDOM*10/32768 ; echo $number

使用set查看所有变量(含环境变量与自定义变量)

PS1(提示符的设置)

命令提示符,也就是我们常见的[root@www ~]#[user ~]$的设置值

  • \d:可显示星期月日的日期格式
  • \H:完整的主机名
  • \h:仅取主机名在第一个小数点之前的名字
  • \t:显示时间,为24小时制"HH:MM:SS"
  • \T:12小时格式”HH:MM:SS"
  • \A:24小时“HH:MM"
  • @:12"am/pm"
  • \u:目前用户的账号名称
  • \v:BASH的版本信息
  • \w:完整的工作目录名称,由根目录写起
  • \W:利用basename函数取得工作目录名称,所以仅仅会列出最后一个目录名
  • \#:执行的第几个命令
  • \$:提示符,如果是root就是#

[root@www /home/user 22:45 #12]#

PS1=`[\U@\h \w \A #\#]\$`

$(关于本shell的PID)

[root@VM-4-12-centos ~]# echo $$
23365

?(关于上个执行命令的回传码)

这个变量是上一个执行的命令所回传的值

当我们执行某些命令时,这些命令都会回传一个执行后的代码。一般来说,如果执行成功该命令,则会回传一个0值,如果执行过程发生错误,就会回传错误代码。一般就是以非0的数字来代替

hpBook:~ # echo $HOME
/root
hpBook:~ # echo $?
0
hpBook:~ # mail
If 'mail' is not a typo you can use command-not-found to lookup the package that contains it, like this:
cnf mail
hpBook:~ # echo $? # mail命令发生错误,返回错误码127
127
hpBook:~ # echo $?
0

OSTYPE、HOSTTYPE、MACHTYPE(主机硬件与内核的等级)

个人计算机的CPU主要分为32位和64位,其中32位分为i386、i586、i686。64位称为x86_64

较高级的硬件通常会向下兼容旧有的软件,但较高级的软件可能无法安装在旧机器上安装。

export:自定义变量转成环境变量

环境变量与自定义变量的主要区别在于该变量是否会被子进程所继续引用

当登录Linux并取得一个bash后,此时的这个bash就是一个独立的进程,被称为PID,接下来在这个bash下执行的任何命令都是由这个bash所衍生出来的,那些被执行的命令就成为子进程

image-20240108231445143

我们在原本的bash下面再执行一个bash,结果操作的环境接口就会跑到第二个bash(子进程),原本的bash就会处于暂停的状态(sleep)。想要回到原本的bash去,就只有将第二个bash结束掉(exit或logout)

子进程仅会继承父进程的环境变量,不会继承父进程的自定义变量

export 变量名称 # 使该变量成为环境变量

影响显示结果的语系变量(locale)

locale -a # 查看Linux支持的所有语系

/etc/sysconfig/i8n # 整体系统默认的语系定义

无论如何,如果发生一些乱码问题,那么设置系统里面保有的语系编码,例如en_US

变量的有效范围

为什么环境变量的数据可以被子进程所引用呢?这是因为与内存配置有关

  • 当启动一个shell,操作系统会分配一记忆块给shell用,此内存内的变量可以让子进程取用
  • 若在父进程使用export,可以让自定义变量的内容写入到上述的记忆块中(环境变量)
  • 当加载另一个shell时,即启动子进程离开父进程,子shell可以将父sehll的环境变量所在的记忆块导入到自己的环境变量块当中

要注意的是,这个”环境变量“与”bash的操作环境“意思不太一样,举例来说,PS1并不是环境变量,但PS1会影响到bash的接口(提示符)

变量键盘读取、数组与声明:read、array、declare

read

读取来自键盘的输入量。就比如某些程序执行的过程当中,会等待用户输入yes/no之类的信息

-p:后面接提示符
-t:可以接等待的秒数
hpBook:~ # read -p "Please enter your name:" -t 30 named
Please enter your name:123
hpBook:~ # echo $named
123
# 提示用户30秒内输入name,让后将name的内容保存在named变量中

declare/typeset

声明变量的类型

declare [] var
-a:将var定义为数组
-i:定义为整数数字
-x:用法与export一样,将var变为环境变量
-r:将var设置为readonly类型,该变量不可以被更改,也不能被重设
hpBook:~ # num=1+2
hpBook:~ # echo $num
1+2 # 此时num为文字类型
hpBook:~ # declare -i num=1+2
hpBook:~ # echo $num
3

变量类型默认为字符串

bash环境中的数值运算,默认最多仅能到达整数类型,所以三分之一结果为0

declare +x num # 将-变为+可以进行取消操作,即原本为整数数字类型的num取消为字符串
declare -p num # 列出num的变量类型

如果不小心把变量设置为只读,通常需要注销再登录才可以复原该变量的类型

数组(array)变量类型

数组的设置方式:

var[index]=content

意思是,我有一个名为var的数组,这个数组的内容为var[1]=“one”,var[2]="two"等等,index就是一些数字,重点使用[]来设置的

与文件系统及程序的限制关系:ulimit

为了防止多用户同时占用过多资源,bash可以通过ulimit来限制用户的某些系统资源,包括可以打开的文件数量、可以使用的CPU时间、可以使用的内存总量等

-H:必不能超过这个数值
-s:警告设置,超过后会有警告提示
-a:后面不接任何参数,可以列出所有的限制额度
-c:当某些进程发生错误时,系统可能会将该进程在内存中的信息写成文件(内核文件)
-f:此shell可以创建的最大文件容量(一般为2GB)
-d:进程可使用的最大断裂内存容量
-l:可用于锁定的内存量
-t:可使用的最大CPU时间(单位为秒)
-u:单一用户可以使用的最大进程数量

要想复原ulimit的设置最简单的方法就是注销再登陆,否则就得重新设置ulimit

变量内容的删除、替代与替换

变量内容的删除与替换

例子

image-20240109212428755

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/root/bin

说明

${path#/*kerberos/bin:}

$是关键字,用在这种删除模式中

${path#/*kerberos/bin:}

path是原本的变量名称

${path**#**/*kerberos/bin:}

#代表从变量内容的最前面开始向右删除,仅删除最短的那个

${path#/*kerberos/bin:}

代表要被删除部分,由于# 代表由前面开始删除,所以这里便由开始的 / 写起。

需要注意的是,我们还可以通过通配符 * 来替代 0 到无穷多个任意字符

2.删除前面所有的目录,仅保留最后一个目录

${path**#**/*:}

删除从第一个/到最短匹配到:之间的所有内容

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

${path**##**/*:}

删除从第一个/到最长匹配到:之间的所有内容

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

3.从后面向前删除变量内容

${path%:*bin}

删除从最后的:到bin为止最短匹配的bin

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

${path%%:*bin}

/usr/kerberos/sbin~~:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin~~

替换

${path/sbin/SBIN} 两个斜线之间的是旧字符串

/usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

${path//sbin/SBIN}

/usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/SBIN:/usr/local/bin:/SBIN:/bin:/usr/SBIN:/usr/bin:/root/bin

image-20240110225155712

变量的测试与内容替换

在某些时刻我们需要判断某个变量是否存在。若变量存在则使用现有的变量,若不存在则给予一个常用的设置

hpBook:~ # echo $username

hpBook:~ # username=${username-root}
hpBook:~ # echo $username # 此时username可能不存在,也可能为空字符串。此时主动给予root的内容
root
hpBook:~ # username='123'
hpBook:~ # username=${usrname-root}
hpBook:~ # echo $username # username被设置了123值,所以不给予值
123

格式:new_var=${old_var-content}

hpBook:~ # username=''
hpBook:~ # username=${username-root}
hpBook:~ # echo $username

hpBook:~ # username=${username:-root} # 加上:后若变量内容为空或者是未设置,都能够以后面的内容替换
hpBook:~ # echo $username
root

加上冒号后,被测试的变量未被设置或者已被设置为空字符串时,都能够用后面的内容来替换与设置

image-20240110232633342

命令别名与历史命令

命令别名设置:alias,unalias

alias的定义规则几乎与变量定义规则相同

alias command1=‘command2’

取消的话就用unalias command2

历史命令:history

n:列出最近的n条命令
-C:将目前shell中的所有history内容全部删除
-a:将目前新增的history命令新增入hisfiles中,默认写入~/.bash_history
-r:将 histfiles 的内容读取目前这个 shell 的 history 记忆中
-w:将目前的 history 记忆内容写入 histfiles 中

~/.bash_history中记录的条数由HISTSIZE决定,旧的信息会被主动去掉,仅保留最新的

# 执行历史命令
!number
!command # 由最近的命令向前搜寻命令为command的命令
!! # 执行上一个命令

Bash Shell的操作环境

路径与命令查找顺序

我们的系统里面其实有不少的ls命令,如果一个命令(如ls)被执行时,到底是哪一个ls被执行了呢

基本上,命令运行有这样的顺序:

  1. 以相对/绝对路径执行命令,如/bin/ls或./ls
  2. 由alias找到该命令
  3. 由bash内置的(builtin)命令执行
  4. 通过$PATH的顺序来找到第一个命令执行

image-20240111000017194

root@Redrock-ButterBeer:~# type -a rm
rm is aliased to `rm -i'
rm is /usr/bin/rm
rm is /bin/rm
# 可以通过type -a查询命令查找的顺序

bash的登陆与欢迎信息:/etc/issue,/etc/motd

登陆界面,保存在/etc/issue

root@Redrock-ButterBeer:~# cat /etc/issue
Debian GNU/Linux 12 \n \l

image-20240111211216275

如果你想让用户登陆后取得一些信息,可以将信息加入到/etc/mtod

连接主机...
连接主机成功
Linux Redrock-ButterBeer 6.1.0-13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.55-1 (2023-09-29) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
___ _ _ ___ _ _ ___
| _ \___ __| |_ _ ___ __| |_____| _ )_ _| |_| |_ ___ _ _| _ ) ___ ___ _ _
| / -_) _` | '_/ _ \/ _| / /___| _ \ || | _| _/ -_) '_| _ \/ -_) -_) '_|
|_|_\___\__,_|_| \___/\__|_\_\ |___/\_,_|\__|\__\___|_| |___/\___\___|_|

当我们使用telnet连接到主机时,显示的是/etc/issue.net的内容

bash的环境配置文件

  • login与non-login shell

    login shell:取得bash时需要完整的登录流程,就称为login shell。
    举例来说,你要由tty1-tty6登录,需要输入用户的账号与密码,此时取得的bash就成为”login shell“

  • non-login shell

    取得bash接口的方法不需要重复登录的操作。在原本的bash下再次执行bash这个命令,再次取得的bash就称为non-login shell

这两个取得的bash,各自读取的配置文件数据是不一致的

login shell只会读取这两个配置文件

  • /etc/profile:这是系统整体的设置

    这个文件可以利用用户的标识符UID来决定很多重要的变量数据,这个文件中设置的变量有

    • PATH:会依据UID决定PATH变量要不要含有sbin的系统命令目录
    • MAIL:依据账号设置好用户的mailbox到/var/spool/mail/账号名
    • USER:根据用户的账号设置此变量内容
    • HOSTSIZE:历史命令条数
    • 它还会调用外部的设置数据,在CentOS 5.x中,以下数据会依照顺序被调用进来
      • /etc/inputrc:这个文件并没有被执行,这个文件会主动判断用户有没有自定义输入的按键功能,如果没有的话,/etc/profile就设置”INPUTRC=/etc/inputrc“这个变量
      • /etc/profile.d/*sh:只要在profile.d这个目录内且扩展名为sh,另外用户能够具有r的权限,那么文件就会被/etc/profile调用。在CentOS 5.x中,这个目录下面的文件规定了bash操作接口的颜色、语系、ll与ls命令的命令别名、vi的命令别名等,如果需要帮所有用户设置一些共享的命令别名时,可以在这个目录下面自行创建扩展名为.sh文件
      • /etc/sysconfig/i18n:这个文件是由/etc/profile.d/lang.sh调用的。这是决定bash默认使用何种语系的重要配置文件,文件里最重要的就是LANG这个变量的设置。
  • 个人偏好设置文件:~/.bash_profile

    bash在读完/etc/profile后并借此调用其他配置文件后,接下来则会读取用户的个人配置文件。

    在login shell的bash环境中,所读取的个人偏好配置文件其实主要有三个:

    • ~/.bash_profile
    • ~/.bash_login
    • ~/.profile

    bash的login shell设置只会读取上面三个文件的其中一个,而读取的顺序则是依照是上面的顺序

    [root@VM-4-12-centos ~]# cat ~/.bash_profile
    # .bash_profile

    # Get the aliases and functions
    if [ -f ~/.bashrc ]; then
    . ~/.bashrc
    fi

    # User specific environment and startup programs

    PATH=$PATH:$HOME/bin

    export PATH # 这里使用累加的方式增加用户主文件夹下的~/bin/为额外的执行文件放置目录

    # 判断主文件夹下的~/.bashrc是否存在,如果存在则读入~/.bahsrc的设置

    整个login shell的读取流程

image-20240111221747850

source:读取环境配置文件的命令

当改动配置文件后,通常需要注销后再登录才能生效。source可以直接读取配置文件而不注销登录

source ~/.bashrc
. ~/.bashrc
# 两种效果相同

~/.bashrc(non-login shell会读)

[root@VM-4-12-centos ~]# cat ~/.bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
export NSS_STRICT_NOFORK=DISABLED
alias php74='php74 -c /www/server/php/74/etc/php-cli.ini'

此外CentOS 5.x会主动调用/etc/bashrc这个文件,因为该文件为bash定义下面的数据

  • 依据不同的UID规定umask的值
  • 依据不同的UID规定提示符(就是PS1)
  • 调用/etc/profile.d/*.sh的设置

其他相关配置文件

  • /etc/man.config:规定了使用man的时候man page的路径到哪里去寻找。其实就是执行man的时候该去哪里查看数据的路径设置

    我们在查找man page时,会依据MANPATH的路径去分别查找

  • ~/.bash_history:默认情况下,历史命令会被记录在这里。而这个文件可以记录多少命令由HISTSIZE决定

  • ~/.bash_logout:记录当我注销bash后系统再帮我做完什么操作后再离开。默认情况下,bash只是帮我们清理掉屏幕的信息而已。

终端机的环境设置:stty,set

stty

在登录时我们可以取得一些字符设置的功能,比如我们可以使用退格键来删除命令行的字符,也可以使用ctrl+c来强制终止一个命令的运行等。我们可以通过stty来设置一些按键功能

-a:将所有stty参数列出来
hpBook:~ # stty -a
speed 38400 baud; rows 29; columns 112; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

^代表Ctrl的意思

  • eof:end of file,代表结束输入
  • erase:向后删除字符
  • intr:送出一个interrupt中断信号给目前正在运行的程序
  • kill:删除目前命令行上的所有文字
  • quit:送出一个quit信号给目前正在运行的进程
  • start:在某个进程停止后,重新启动它的输出
  • stop:停止目前屏幕的输出
  • susp:送出一个terminal stop的信号给正在运行的进程

set

set除了可以查看变量内容外,还可以帮我们设置整个命令输入/输出的和环境,如历史命令、显示错误内容等

image-20240113163134080

想取消参数的话,前面加+

另外,其他的按键设置功能放置在/etc/inputrc中

还有例如/etc/DIR_COLORS*与/etc/termcap等

bash默认的组合键

image-20240113163526581

通配符与特殊符号

符号 意义
* 代表0到无穷多个任意字符
? 代表一定有一个任意字符
[] 代表一定有一个在中括号内的字符(非任意字符)。例如[abcd]一定有abcd的其中一个
[-] 代表在编码顺序内的所有字符。例如[0-9]代表0到9之间的所有数字
[^] 表示原向选择,例如[^abc]表示一定有一个字符,只要是非abc就接受
# 找出/etc下面文件名刚好是5个字符的文件名
ls /etc/?????

# 找出/etc下文件名含有数字的文件名
ls /etc/*[0-9]* # 注意要加*

# 找出/etc下文件名开头非为小写字母的文件名
ls /etc/*[^a-z]*

其他的特殊符号

符号 内容
# 注释
\ 转义
| 管道(pipe),分割两个管道命令的界定
; 连续命令执行分隔符
~ 用户的主文件夹
$ 使用变量前导符
& 作业控制,将命令变成背景下工作
! 逻辑运算"非"
/ 目录符号,路径分隔
>,>> 数据流重定向,输出导向,分别是“替换”与“累加"
<,<< 输入导向
‘’ 不具有变量置换功能
“” 具有变量置换功能
`` 两个“`”中间为可以先执行的命令,也可以使用$()
() 中间为子shell的起始与结束
{} 在中间为命令块的组合

数据流重定向

就是将某个命令执行后应该要出现在屏幕上的数据传输到其他地方,例如文件或者设备等

什么是数据流重定向

命令的执行过程

image-20240113170445932

我们在执行一个命令时,这个命令可能会由文件读入数据,经过处理后,再将数据输出到屏幕上

  • standard output与standard error output(标准输出与标准错误输出)

    标准输出指的是命令执行所后回传的正确的信息,而标准错误输出可理解为命令执行失败后,所回传的错误信息。

  • 我们的系统中有a.sh这个文件,但没有b.sh。当执行cat a.sh b.sh时,cat会进行标准输出和标准错误输出,此时不管正确还是错误的数据都是默认输出到屏幕上,而数据流重定向功能就可以将standard output(stdout)与standard error output(stderr)分别传送到其他的文件或设备去,而分别传送所用的特殊字符则如下所示:

    1. 标准输入(stdin):代码为0,使用<或<<
    2. 标准输出(stdout):代码为1,使用>或>>
    3. 标准错误输出(stderr):代码为2,使用2>或2>>

重定向文件的创建方式

cat test1.txt > test2.txt

当test2.txt不存在时,系统会自动创建。如果存在,则会先将test2.txt的内容清空后,再将数据写入。如果不想清空数据,使用>>累加内容就好

通过2>或2>>可以将错误的数据输出到指定的文件或设备

目录下没有abc.sh存在abcd.sh

hpBook:~/.ssh # vim abcd.sh
hpBook:~/.ssh # cat abc.sh > abcd.sh
cat: abc.sh: No such file or directory

# 错误信息并没有输入到abcd.sh中
# 改成2>就可以了
hpBook:~/.ssh # cat abc.sh 2> abcd.sh
hpBook:~/.ssh # more abcd.sh
cat: abc.sh: No such file or directory
# 可以看到错误信息被记录在了abcd.sh中

# 还可以把正确与错误的数据分别存入不同的文件中
ls abc.sh > list_right.txt 2> list_error.txt

/dev/null 垃圾桶黑洞设备与特殊写法

/dev/null可以吃掉任何导向这个设备的信息,我们可以把错误信息导向这里,从而达到忽略而不占内存的效果

hpBook:~/.ssh # cat abc.sh abcd.sh
cat: abc.sh: No such file or directory
This is a existed file.
Redirect:cat: abc.sh: No such file or directory
hpBook:~/.ssh # cat abc.sh abcd.sh 2> /dev/null
This is a existed file.
Redirect:cat: abc.sh: No such file or directory # 只显示stdout,而stderr被抛弃了

如果想将正确与错误的数据通通写入同一个文件中,这时候需要使用特殊的写法

find /home -name .bashrc > list 2> list # 错误的
find /home -name .bashrc > list 2>1&
find /home -name .bashrc &> list

第一条错误的原因是由于两条数据同时写入一个文件,但没有使用特殊语法,此时两条数据可能会交叉写入该文件内,造成次序的错乱。里面的数据排列是混乱的。

一般常用第二种写法,即2>1&

standard input,<与<<

将原本需要由键盘输入的数据改由文件内容来替代

root@orangepizero3:~# cat > catfile
this is a catfile. # 此时用户使用键盘在屏幕上输入的信息会被直接写入catfile中
root@orangepizero3:~# cat catfile
this is a catfile.

也可以用某个文件的内容来替代键盘的敲击

root@orangepizero3:~# cat catfile
hello
root@orangepizero3:~# cat catfile2
world
root@orangepizero3:~# cat > catfile2 < catfile # 替代内容
root@orangepizero3:~# cat catfile2
hello

<< 代表结束输入

# 我想用cat直接将输入的信息输出到catfile中,且当有键盘输入eof时,本次输入就结束
root@orangepizero3:~# cat > catfile << "eof"
> this is a test.
> now stop
> eof
root@orangepizero3:~# cat catfile
this is a test.
now stop # 可以看到eof没有被输入进文件中

用途

  1. 屏幕输出的信息需要保存
  2. 后台执行中的程序,不希望它干扰屏幕的正常输出结果
  3. 一些系统的例行命令的执行结果希望保存下来
  4. 一些执行命令的可能已知错误信息,想以2>/dev/null将它丢掉
  5. 错误信息与正确信息需要分别输出

命令执行的判断依据: ; , && ||

  • cmd ; cmd

    命令连续执行,前后命令可以没有相关性

  • $?(命令回传码)与&&或||

    若前一个命令执行的结果正确,在Linux下会回传一个$?=0的值。

    image-20240124165450709

    ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe

    Linux下面的命令都是从左往右执行的

    1. 当/tmp/abc存在时,不执行mkdir,此时继续向后执行命令touch
    2. 当/tmp/abc不存在,执行mkdir,第二条命令被成功执行,然后执行touch

image-20240124170341333

一般的假设判断式

cmd1 && cmd2 || cmd3

比如ls /tmp/test && echo “exist” || echo “no exist”

判断/tem/test是否存在,存在显示exist,不存在就显示no exist

管道命令(pipe)

"|"仅能处理由前面一个命令传来的正确信息,而错误信息没有直接处理的能力。

管道命令必须要能够接收来自前一个命令的数据成为standard input继续处理才行。

管道命令必须要能够接收standard input的数据才行,比如less,more,head等。

选取命令:cut,grep

通常针对”行”来分析的,而不是整篇分析

cut

cut -d'分隔字符' -f fields
cut -c 字符范围

-d:
-f:依据-d的分隔字符将一段信息切割成为数段,用-f取出第几段
-c:以字符的单位取出固定字符区间

# 将PATH变量的第3个路径取出
root@orangepizero3:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
root@orangepizero3:~# echo $PATH | cut -d ':' -f 3
/usr/sbin

# 输出export的第12个字符以后的字符串
root@orangepizero3:~# export
declare -x HOME="/root"
declare -x LANG="en_US.UTF-8"
declare -x LANGUAGE="en_US.UTF-8"
root@orangepizero3:~# export | cut -c 12-
HOME="/root"
LANG="en_US.UTF-8"
LANGUAGE="en_US.UTF-8"

主要用于将同一行里面的数据进行分解,最常使用在分析一些数据或文字数据的时候。使用时要注意空格也要算入。

grep

用来分析一行信息

grep -参数 '查找字符串' filename
-a:将二进制文件以text文件的方式查找数据
-c:计算找到查找字符串的次数
-i:忽略大小写的不同
-n:顺便输出行号
-v:反向选择。即选出没有'查找字符串'的那一行
--color=auto

排序命令:sort,wc,uniq

sort

sort -参数 [file or stdin]
-f:忽略大小写
-b:忽略最前面的空格
-M:以月份的名字来排序
-n:使用纯数字排序
-r:反向排序
-u:就是uniq,相同的数据仅输出一行代表
-t:分隔符
-k:以那个区间来排序

# 在/etc/passwd中,以:为分隔,以第三列排序
root@orangepizero3:~# cat /etc/passwd | sort -t ':' -k 3

uniq

排序完成后,将重复的数据仅列出一个显示。

-i:忽略大小写
-c:进行计数

# 使用last将账号列出,仅取出账号列,并输出每个人的登录总次数
root@Redrock-ButterBeer:~# last | cut -d ' ' -f1 | sort | uniq -c # f1表示指定要提取的是每行的第一个字段
1
12 reboot
1278 root
1 wtmp

wc

可以帮我们知道某个文件里有多少字,多少行

-l:仅列出行
-w:仅列出多少字
-m:多少字符

root@orangepizero3:~# cat /etc/passwd | wc
33 43 1747
# 有33行,43个字数,1747个字符数

双向重定向:tee

如果想要将某个数据流的处理过程中将某段信息存下来,可以利用tee

-a:累加数据到file中

ls -l | tee -a ~/homefile | more
# 将ls的输出累加到homefile中,同时屏幕也有输出信息

字符转换命令:tr,col,join,paste,expand

tr

用来删除一段信息中的文字,或者替换

tr [-ds] SET1 ...

-d;删除信息中的SET1字符串
-s:替换重复的字符


# 将last输出中所有的小写字符变成大写字符
last | tr [a-z] [A-Z]

# 删除/etc/password输出中的冒号
cat /etc/password | tr -d ':'

col

-x:将tab转换成对等的空格
-b:在文字内有反斜杠'\'时,仅保留反斜杠最后接的那个字符

# 一种是用来将tab转换为对等的空格键
cat /etc/man.config | col -x | cat -A | more

# 另一种是用来将man page转成纯文本文件方便查阅
man col | col -b > /root/col.man

join

处理两个文件之间的数据,主要是将两个文件中相同数据的那一行加在一起。

-t:以什么为分隔数据,并且对比第一个字段的数据
-i:忽略大小写差异
-1:代表第一个文件要用哪个字段来分析
-2:第二个文件用哪个字段来分析

paste

不对比两个文件的相关性,直接将两个文件的两行贴在一起。

expand

将[tab]转为空格键

切割命令:split

可以将一个文件依据文件大小或行数来切割成为小文件。

-b:接欲切割成的文件大小,可加单位
-l:依据行数切割
PREFIX:代表前导符,可作为切割文件的前导文字。

# 将ls -al /的输出信息,每15行记录成一个文件
[root@VM-4-12-centos ~]# ls -al / | split -l 15 - lsroot
[root@VM-4-12-centos ~]# wc -l lsroot*
15 lsrootaa
15 lsrootab
3 lsrootac
33 总用量

# 如果需要stdout/stdin但没有文件时,-会被认为是stdout/stdin

参数代换:xargs

用来产生某个命令的参数

xargs 是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令。

之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有这个必要,所以就有了 xargs 命令

Linux xargs 命令 | 菜鸟教程 (runoob.com)

# 复制所有图片文件到 /data/images 目录下:
# 这个命令首先使用ls *.jpg列出当前目录中所有以.jpg结尾的文件,然后将这些文件作为参数传递给xargs命令。-n1选项告诉xargs每次只传递一个参数给cp命令,-I {}选项指定了用{}来代替传递的参数。最后,cp {} /data/images将每个.jpg文件复制到/data/images目录下。
ls *.jpg | xargs -n1 -I {} cp {} /data/images

# 用 rm 删除太多的文件时候,可能得到一个错误信息:/bin/rm Argument list too long. 用 xargs 去避免这个问题。xargs -0 将 \0 作为定界符
# -print0选项是find命令的一个参数,它用于在输出文件路径时使用空字符(null字符,ASCII码为0)来分隔文件名,而不是默认的换行符。
# 通过指定-type f,find命令将只查找并返回普通的文件,不包括目录、符号链接等其他文件类型。
find . -type f -name "*.log" -print0 | xargs -0 rm -f

# 统计一个源代码目录中所有 php 文件的行数:
find . -type f -name "*.php" -print0 | xargs -0 wc -l

# 查找所有的 jpg 文件,并且压缩它们:
find . -type f -name "*.jpg" -print | xargs tar -czvf images.tar.gz

# 假如你有一个文件包含了很多你希望下载的 URL,你能够使用 xargs下载所有链接:
cat url-list.txt | xargs wget -c

关于减号 - 的用途

减号作为标准输入/输出的替代符号:在一些命令或管道操作中,减号(-)有时表示标准输入或标准输出的替代符号。例如,在tar命令中使用-来代表标准输入或输出流,比如tar -cvf - /home中的-表示将打包结果输出到标准输出。

tar -cvf - /home | tar -xvf -

我们将/home里面的文件打包,但打包的数据不是记录到文件里,而是传送到stdout;经过管道后,将tar -cvf - /home传送到后面的tar -xvf -。后面的-则是取用前一个命令的stdout,因此就不用使用文件了。

正则表达式与文件格式化处理

基础正则表达式

使用正则表达式时,要特别注意留意当时环境的语系时什么,否则可能会出现不同的选取结果。

一般练习正则表达式时,因为兼容的是POSIX的标准,所以使用LANG=C

特殊符号 代表意义
[:alnum:] 代表英文大小写和数字,即0-9,A-Z,a-z
[:alpha:] A-Z,a-z
[:upper:] A-Z
[:lower:] a-z
[:digit:] 0-9

基础正则表达式字符

grep高级用法

-A:后接数字,为after的意思,罗列除本行外的后续n行
-B
--color=auto

# 用dmesg显示内核信息,grep筛选出含eth行,并用颜色区分,加上行号表示
dmesg | grep -n 'eth' --color=auto

sed工具

sed [-nefr] [动作]
-n:只有经过sed特殊处理的一行才会被列出来
-e:直接在命令行模式进行sed动作编辑
-f:将sed动作写入一个文件
-r:支持扩展性正则表达式语法
-i:直接修改读取的文件内容,而不是屏幕输出

动作说明:[n1][,n2]function
在n1到n2之间进行动作,动作必须得用两个单引号括住
function包括:
a:新增,下一行出现
c:替换,接字符串,可以替换n1到n2之间的行
d:删除,不接参数
i:插入。上一行出现
p:打印,通常与-n连用
s:替换

# 删除2-5行
sed '2,5d'

# 在第二行后增加两行
sed '2a drink tea' \
> drink coffee ?

# 替换2-5行
sed '2,5c hello'

# 列出5-7行
sed '5,7p'
# 列出5-7行
sed '5,7p'

# sed 's/要被替换的字符串/新的字符串/g'


ip a | grep 172.20.14.4
inet 172.20.14.4/24 brd 172.20.14.255 scope global vmbr0
# 只保留172.20.14.255
ip a | grep 172.20.14.4 | sed 's/^.*brd//g' | sed 's/scope.*$//g'
# 两个斜杠 // 表示将匹配的内容替换为空,$表示行尾,^表示开头
# .* 则表示匹配前面的字符(在这里是 . )零次或多次,直到行尾($)

sed修改文件内容

# 最后一行新增
sed -i '$a # This is a test' mine.txt
# $表示最后一行,a表示新增操作

# 将mine.tx每一行最后一个.改为!
sed -i 's/\.$/\!/g' mine.txt

s/: 表示替换。
\.: 匹配一个句点字符。这里的反斜杠(\)是为了转义句点,因为句点在正则表达式中是一个特殊字符,表示匹配任意单个字符。
/\!/: 替换为感叹号。
g: 表示全局替换,即替换每一行中所有的匹配项,而不只是第一个。

扩展正则表达式egrep

grep -v '^$' mine.txt | grep -v '^#'
# 使用egrep一次查找。通过|
egrep -v '^$|^#' mine.txt

# 如果想查出来文件中含有!与>的行时
egrep -n '[!>]' mine.txt

文件的格式化与相关处理

格式化打印printf

和C语言用法一致,通常和awk搭配使用

awk:数据处理工具

awk倾向于将一行分成数个字段来处理,sed常常作用于一整行的数据处理

awk '条件类型1{动作1} 条件类型2{动作2}' filename

整个awk的处理流程:

  1. 读取第一行,并将第一行的数据填入$0 $1 $2等变量当中
  2. 依据条件类型的限制,判断是否需要进行后面的动作
  3. 做完所有的动作与条件类型
  4. 若还有后续的”行“的数据,则重复上面1—3的步骤,知道所有的数据都读完
  5. 默认分隔符为空格键或[tab]键
root@master1:~# last -n 5
root pts/1 172.22.160.176 Sat Aug 17 22:29 still logged in
root pts/0 172.22.160.176 Sat Aug 17 22:29 still logged in
root pts/1 172.22.160.101 Fri Aug 16 19:03 - 19:49 (00:45)
root pts/0 172.22.160.101 Fri Aug 16 19:03 - 19:49 (00:45)
root pts/3 172.22.160.176 Wed Aug 14 12:23 - 13:13 (00:50)

wtmp begins Sun May 26 23:47:55 2024
root@master1:~# last -n 5 | awk '{print $1 "\t" $3}'
root 172.22.160.176
root 172.22.160.176
root 172.22.160.101
root 172.22.160.101
root 172.22.160.176

wtmp Sun

awk如何知道有几行几列,通过内置变量

变量名称 代表意义
NF 每一行($0)拥有的字段总数
NR 目前awk所处理的是”第几行数据“
FS 目前的分隔符,默认是空格

awk的格式内容如果想要以print打印时,记得非变量的文字部分,包含一小节printf提到的格式中,都需要使用双引号来定义出来(就和C语言的printf格式化输出一样),因为单引号已经是awk的命令固定用法。

root@master1:~# last -n 5 | awk '{print $1 "\t lines:" NR "\t columes:" NF}'
root lines:1 columes:10
root lines:2 columes:10
root lines:3 columes:10
root lines:4 columes:10
root lines:5 columes:10
lines:6 columes:0
wtmp lines:7 columes:7

awk也有逻辑运算符

在awk中,变量可以直接使用,不需要$

文件比较工具

diff

通常用在同一的文件(或软件)的新旧版本区别上

diff -[bBi] from-file to-file

from-file:想要比较的文件
to-file:目的比较文件

-b:忽略一行当中有多个空白的泣别(about me和about me视为相同)
-B:忽略空白行的区别
-i:忽略大小写的不同


root@master1:~/yiiong# cat test.old
1
2
3
4
5
6
root@master1:~/yiiong# cat test.new
1
2

4
5
no six line!
root@master1:~/yiiong# diff test.old test.new
3c3
< 3
---
>
6c6
< 6
---
> no six line!


3c3 表示第三行在两个文件中都有所不同(c 表示变更)。
< 3 表示在 test.old 文件中第三行的内容是 3。
--- 分隔符用来区分两个文件的不同部分。
> 表示 test.new 文件中的相应位置是空白行。

6c6 表示第六行在两个文件中都有所不同。
< 6 表示在 test.old 文件中第六行的内容是 6。
--- 分隔符用来区分两个文件的不同部分。
> no six line! 表示 test.new 文件中的相应位置是 no six line!。
总结一下,diff 的输出告诉我们:
在 test.old 文件的第三行原本是数字 3,但在 test.new 文件中第三行变成了空白行。
在 test.old 文件的第六行原本是数字 6,但在 test.new 文件中第六行变成了 no six line!。

cmp

以“字节”为单位比较,通常用来比较而二进制文件。diff以“行”为单位比较。

patch

与diff搭配,比如先用diff比较出新旧版本的区别,并将区别文件制作成为补丁文件,再由补丁文件更新旧文件即可。

diff制作出来的比较文件通常使用扩展名.patch,新文件看到-会删除,看到+会加入。

# 制作补丁
root@master1:~/yiiong# diff -Naur test.old test.new > test.patch
-N: 表示即使文件在其中一个文件夹中不存在也要报告差异。这通常用于比较两个目录的内容,确保即使一个文件在一个目录中不存在也会被标记为差异。
-a: 表示将所有文件视为文本文件,并尝试进行文本比较,即使它们实际上可能是二进制文件。
-u: 表示使用统一格式输出差异。这会提供更多的上下文行,使得差异更容易理解。
-r: 表示递归地比较子目录。
root@master1:~/yiiong# cat test.patch
--- test.old 2024-08-17 23:16:41.482797614 +0800 # 新旧文件信息
+++ test.new 2024-08-17 23:17:21.191871581 +0800
@@ -1,6 +1,6 @@
1
2
-3 # 左侧文件删除
+ # 右侧文件加入
4
5
-6
+no six line!

patch -pN < patch_file # 更新
patch -R -pN # 还原

# 更新
root@master1:~/yiiong# patch -p0 < test.patch
patching file test.old
root@master1:~/yiiong# cat test.old
1
2

4
5
no six line!
# 还原
root@master1:~/yiiong# patch -R -p0 < test.patch
patching file test.old
root@master1:~/yiiong# cat test.old
1
2
3
4
5
6

文件打印准备:pr

学习shell script

Linux账号管理与ACL权限控制

Linux的账号与用户组

用户标识符:UID与GID

每个登录的用户至少都会获得两个ID:用户ID(User ID)、用户组ID(Group ID)

每一个文件都会有所谓的所有者ID和用户组ID,当我们有要显示文件属性的需求时,系统会依据/etc/passwd与/etc/group的内容,找到UID/GID对应的账号与组名再显示出来。

用户账号

输入账号密码后,系统处理流程

  1. 先找/etc/passwd里有没有账号,没有则跳出。如果有的话将该账号对应的UID/GID(在/etc/group里)读出来。另外,该账号的主文件夹和shell设置也一起读出来。
  2. 核对密码表。进入/etc/shadow里面照对应的账号和UID,然后核对是否相符。
  3. 如果一切顺利,则进入shell的管控阶段。

/etc/passwd管理用户UID/GID,/etc/shhadow专门管理密码相关数据。

/etc/passwd文件结构

权限设置-rw-r–r–

每一行代表一个账户,有几个行就有几个账号。里面有一些系统账号,例如bin、daemon、adm、nobody

root@master1:~# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
......

一共七个字段,用:分隔

  1. 账号名称:就是账号,用来对用UID

  2. 密码:数据被保存在/etc/shadow里,所有有一个x

  3. UID:用户标识符。
    0就是系统管理员,可以有很多个root(不建议)。
    1-499为系统账号,系统账号通常不可登录,所以会有/sbin/nologin这个特殊shell。系统账号分为两种:1-99有distributions自行创建的系统账号。100-499若用户有登录系统账号需求时,可以使用的账号UID

    500-65535:可登录账号。

  4. GID:用来规定组名和GID的对应。

  5. 用户消息说明列:基本没有什么重要用途。

  6. 主文件夹:用户的主文件夹。

  7. Shell

/etc/shadow文件结构

默认权限-rw-------

同样以:分隔,有9个字段

root@master1:~# cat /etc/shadow
root:$y$j9T$IEU0qofFrP52Vg.iH212f/$gWhA6xXAYgf/.8K3GtRge0CdNvRm5PyAikE82L8Uen2:19869:0:99999:7:::
daemon:*:19869:0:99999:7:::
bin:*:19869:0:99999:7:::
......
  1. 账号名称:要与/etc/passwd相同。
  2. 密码:编辑加密过的密码。
  3. 最近更动密码的日期:19869 表示自 1970 年 1 月 1 日以来的天数。
  4. 密码不可被更动的天数(与第三个字段相比):表示这个账号的密码在最近一次被更改后需要经过几天才可以再被修改!如果是0,则随时可以改动。
  5. 密码需要重新更改的天数(与第三个字段相比):为了强制要求用户更改密码。
  6. 密码需要更改期限前的警告天数(与第五个字段相比)
  7. 密码过期后的账号宽限时间(与第五个字段相比):密码有效期为“更新日期(字段三)+重新更改天数(字段五),过了后密码过期,但是还可以使用,只不过会有更改密码的提示。一旦失效就无法登录了。
  8. 账号失效日期
  9. 保留

有效与初始用户组:groups,newgrp

/etc/group文件结构

:分隔,有四列

  1. 用户组名称
  2. 用户组密码:保存在/etc/gshadow
  3. GID
  4. 此用户组支持的账号名称

重要的是第四列。如果同时加入多个用户组,那么在操作时,那么应该以哪个用户组为准?
有效用户组与初始用户组

/etc/passwd里的GID就是所谓的初始用户组(initial group),也就是说当用户登录系统,系统就拥有这个用户组的相关权限。

当用户加入一个新的用户组后,新建文件的组时哪个就要看有效用户组。

groups:有效与支持用户组的查看

groups
第一个输出是有效用户组

newgrp:有效用户组的切换

切换时你想要切换的用户组必须是你已经有支持的用户组。

这个命令可以更改目前用户的有效用户组,而且是以另外一个shell来提供这个功能的。

image-20240818211919470

/etc/gshadow

用来创建组管理员

四个字段

  1. 用户组名
  2. 密码列:!表示无合法密码,所以无用户组管理员
  3. 用户组管理员的账号
  4. 该用户组的所属账号

新增与删除用户:useradd,相关配置文件,passwd,usermod,userdel

useradd

useradd [-u UID] [-g 初始用户组] [-G 次要用户组] [-mM]\
> [-c 说明栏] [-d 主文件夹绝对路径] [-s shell] 用户账号名

image-20240818213513093

当我们使用useradd创建一个账号

  • 在/etc/passwd里面创建一行与账号相关的数据
  • 在/etc/shadow里面将此账号的密码相关参数填入,但还没有密码
  • 在/etc/group里面加入一个与账号名称一模一样的组名
  • 在/home下面创建一个与账号同名的目录作为用户主文件夹,权限为700

然后passwd 账号 给予密码才算完成用户的创建

用useradd添加用户至少会改动的几个文件

  • 用户账号密码相关的:/etc/passwd,/etc/shadow
  • 用户组相关:/etc/group,/etc/gshadow
  • 用户的主文件夹:/home/账号名称

useradd参考文件

/etc/deault/useradd

root@master1:/home# useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/sh
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no
LOG_INIT=yes

GROUP=100:新建账号的初始用户组使用GID为100

CentOS上默认的用户组为与账号名相同的用户组。

  • 私有用户组机制:系统会创建一个与账号一样的用户组给用户作为初始用户组。这种机制比较有保密性,使用这种机制将不会参考GROUP=100这个设置值。代表有CentOS、RHEL。家目录的权限会设置为700
  • 公共用户组机制:以GROUP=100作为新建账号的初始用户组。

HOME=/home:用户主文件夹的基准目录(basedir)

INACTIVE=-1:密码过期后是否会失效的设置值。-1为永远不会失效

EXPIRE=:账号失效日期。如果是付费的会员制系统可以设置。

SHELL=/bin/sh:默认使用的shell程序文件名

SKEL=/etc/skel:用户主文件夹参考基准目录。比如你新建了/etc/skel/www,那么新建用户的主文件夹就会有www这个目录。

CREATE_MAIL_SPOOL=no:创建用户的mailbox

UID/GID和还有密码参数参考/etc/login.defs这个文件

image-20240818222110242

上面的UID_MIN指的是可登录系统的一般账号的最小UID,系统分配UID时,先参考UID_MIN取最小数字,有/etc/passwd查找最大UID,二者相比,然后找出最大的那个再加上1就是新账号的UID。

如果想创建系统用的账号,使用-r参数的时候就会找“比500小的最大的那个UID+1”

useradd时至少会参考:

  • /etc/default/useradd
  • /etc/login.defs
  • /etc/skel/*
  • 还有/eetc/passwd那些

passwd

passwd [--stdin]
passwd [-l] [-u] [--stdin] [-S] \
> [-n 日期] [-x 日数] [-w 日数] [-i 日期] 账号

image-20240818223156481

chage

详细的密码参数显示

image-20240819170120753

usermod

进行账号相关数据的微调

userdel

删除用户

-r:连同用户的主文件夹一起删除

用户功能

finger

查询用户相关信息,大部分都是/etc/passwd里的

finger [-s] username

-s:仅列出用户的账号、全名、终端机代号与登陆时间
-m:列出与后面接的账号相同者

chfn

账号个人信息

chfn [-foph] [账号名]

-f:接真实姓名
-o:办公室房间号
-p:办公室电话
-h:家里电话号码

chsh

change shell

-l:列出可用shell
-s:设置修改自己的shell

id

查询某人的UID/GID

id [useername]

新增与删除用户组

groupadd

groupadd [-g gid] [-r] 用户组名

-g:后面接某个特定GID
-r:新建系统用户组

groupmod

对group相关参数修改

groupdel

gpasswd

用户组管理员

# root可以做的
gpasswd groupname
gpasswd [-A user1,...] [-M user3,...] groupname
gpasswd [-rR] groupname

:若没有任何参数时,表示给予 groupname 一个密码(/etc/gshadow)
-A :将 groupname 癿主控权交由后面的使用者管理(该群组癿管理员)
-M :将某些账号加入这个群组中!
-r :将 groupname 的密码删除
-R :讥 groupname 的密码栏失效

# 用户管理员可以做的
gpasswd [-ad] user groupname
-a:加入
-d:删除

主机的具体权限规划:ACL的使用

针对个人的专属权限

比如user是/pro(权限2770,2是SGID)这个项目的助理,他需要这个项目的内容,但是他不可以修改项目目录内的任何数据。

如果把user放进了支持/pro的用户组里,user拥有/pro的完整权限,他可以删除增加任何内容。

而修改/pro的目录权限后,user可以查阅数据,但是其他所有人均可以进入这个目录查阅数据。

ACL是Access Control List缩写,主要目的是提供传统的owner、group、others的read、write、execute的权限之外的具体权限设置。

它可以针对单一用户、单一文件或目录进行r、w、x的权限设置,对于需要特殊权限的使用状况非常有帮助。

要使用ACL必须有文件系统的支持。

dumpe2fs -h /dev/hda2 # 由superblock内容查询
...
Default mount options: user_xattr acl
...

ACL的设置技巧:getfacl、setfacl

getfacl:取得某个文件/目录的ACL设置项目

image-20240822113516326

setfacl [-bkRd] [{-m|-x} acl参数] 目标文件
-m:设置后续的acl参数给文件
-x:删除后续的acl参数
-b:删除所有的acl
-k:删除默认的acl参数
-R:递归设置acl
-d:设置默认acl
# 1.针对特定用户
# 设置规定是" u:{用户账号列表}:{rwx} "
setfacl -m u:user:rx test.txt
# 设置成功后权限会多一个+

# 无用户列表,代表设置该文件所有者
setfacl -m u::rx test.txt

# 2.针对特定用户组
# 设置规范是" g:{}:{rwx} "
setfacl -m g:mygroup:rx test.txt

# 3.针对有效权限mask的设置
# mask的意思是用户或组所设置的权限必须要存在于mask的权限设置范围内才会生效,此即有效权限
# " m:[rwx] "
setfacl -m m:r test.txt

# 4.针对默认权限的设置
# "d:[ug]:用户列表:[rwx]"
# 让user在/pro下面一直具有rx的默认权限
setfacl d:u:user:rx /pro

引例中可以这样设置

setfacl -m u:user:rx /pro

# 设置成功后可以进入目录查看,但是不能修改数据,也就是写(w)

取消全部的ACL属性

setfacl - b 文件名

用户身份切换

su

su [-lm] [-c 命令] [username]

-:如"su -"代表使用login-shell的变量文件读取方式登录系统
-l:与-类似
-m:-m与-p一样,表示使用目前的环境变量,不读取新用户的配置文件
-c:仅进行一次命令

登录 shell 是当用户通过命令行登录系统时启动的 shell。这种类型的 shell 通常会执行用户的登录脚本,这些脚本可以设置环境变量、定义别名等。

非登录 shell 是在不需要用户登录的情况下启动的 shell。这种类型的 shell 通常不会执行登录脚本,而是在已经存在的 shell 环境中启动的。

image-20240822115542590

image-20240822115553156

image-20240822115459648

  1. 如果要完整地切换到新用户的环境,必须使用su -usernamesu - | username,才会连同/PATH/USER/MAIL等变量都转换成新用户地环境。
  2. 如果仅仅想要执行一次root的命令,可以利用su - -c"命令串"的方式出合理。
  3. 使用root切换成任何用户时,并不需要输入新用户的密码。

sudo

sudo [-b] [u 新用户账号]
-b:将后续的命令让系统自动执行
-u:后面可以接欲切换的用户

# 以sshd身份,在/tmp下面新建一个名为mysshd的文件
sudo -u sshd touch /tmp/mysshd
# 如果是一串命令,可以使用“sh -c”

image-20240822171917573

sudo执行的重点是:

  1. 能否使用sudo,要看/etc/sudoers的设置值。
  2. 可使用sudo的是通过输入用户自己的密码来执行后续的命令串。

visudo与/etc/sudoers

使用visudo修改/etc/sudoers是因为/etc/sudoers是有语法的,如果设置错误会造成无法使用sudo命令。

单一用户可进行root所有命令与sudoers文件语法

# 如果想让user账号可以使用root的任何命令
visudo
...
# 用户账号 登录者的来源主机名=(可切换的身份) 可执行的命令
root ALL= (ALL) ALL # 大约在76行
user ALL= (all) ALL # 添加这一行

利用用户组以及免密码的功能处理visudo

visudo
...
%wheel ALL= (ALL) ALL # 大约在84行
...
%wheel ALL= (ALL) NOPASSWD: ALL #大约在87行
...
# 在最左边加%代表用户组的意思
usermod -a -G wheel pro1

上面的设置会造成任何加入wheel这个用户组的用户就能够使用sudo切换任何身份来操作任何命令。

有限制的命令操作

visudo
myuser ALL= (root) !/usr/bin/passwd, /user/bin/passwd [A-Za-z]*, !/usr/bin/passwd root

意思是myuser可以执行passwd 任意字符,但是passwdpasswd root这两个命令除外,保证myuser不能修改root密码。

通过别名设置visudo

假如我的pro1、pro2、pro3与user1、user2要加入上述的密码管理员的sudo列表中,可以新建一个账户别名为ADMPW的名称,然后处理一下这个名称

visudo
User_Alias ADMPW = pro1, pro2, pro3, user1, user2
Cmnd_Alias ADMPWCOM = !/usr/bin/passwd, /user/bin/passwd [A-Za-z]*, !/usr/bin/passwd root

ADMPW ALL= (root) ADMPWCOM

sudo的时间间隔问题

如果两次sudo的时间间隔超过五分钟,那就需要重新输入一次密码了。这么做是防止第一次执行sudo输入密码后,由于担心用户暂时离开,但有人跑来使用你的账号的原因,所以需要你输入第一次密码重新确认一次身份。

sudo搭配su使用

image-20240822174819602

用户的特殊shell与PAM模块

特殊的shell,/sbin/nologin

“无法登录”指的是这个用户无法使用bash或其他shell来登录,并不是说这个账户就无法使用其他的系统资源。

有些账号像一台提供邮件服务的Linux主机,它上面的账号大部分都是用来接受主机的信件,并不需要登录主机,这个时候就可以用/sbin/nologin作为他们的shell

可以新建/etc/nologin.txt来在用户登录时说明不能登录的原因。

PAM

PAM模块简介

PAM(Oluggable Authentication Modules,嵌入式模块)可以说是一台应用程序编程接口(Application Programming Interface,API),它提供了一连串的验证机制,只要用户将验证阶段的需求告知PAM,它就能回报用户和验证的结果(成功或者失败)

可以在写程序的时候将PAM模块功能加入,就能够利用它的验证功能,目前很多程序都会利用PAM。

PAM模块设置语法

passwd调用PAM的过程

  1. 用户开始执行/usr/bin/passwd,并输入密码
  2. passwd调用PAM模块进行认证
  3. PAM模块到/etc/pam.d/passwd内找寻与程序(passwd)同名的配置文件
  4. 依据/etc/pam.d/passwd内的设置,引用相关的PAM模块逐步进行验证分析
  5. 将验证结果(成功、失败以及其他信息)后回传给passwd这个程序
  6. passwd这支程序会依据PAM回传的结果决定下一个操作(重新输入新密码或者通过验证)

image-20240822195449176

第一个字段:验证类型(Type)

  • auth(authentication):主要用来检验用户的身份验证,后续接的模块都是用来检验用户的身份的
  • account:大部分是在进行authorization(授权),主要是在验证用户是否具有正确的权限。
  • session:通常管理用户在这次登录期间PAM所给予的环境设置。通常用于记录用户登录与注销时的信息。
  • password:用于提供验证的修订工作。就是更改密码。

这四个验证的类型通常有顺序。

第二个字段:验证的控制标志(control flag)

  • required:成功则带有success的标志,失败就是failure,但不论成功或失败都会继续后续的验证流程。由于后续的验证流程可以就行进行,因此相当于有利于数据的登录日志,这也是PAM最常使用required的原因。
  • requisite:与required最大的区别就是失败后不会继续验证。
  • sufficient:与requisite相反,成功则success并终止验证,失败failure则继续。
  • optional:用来显示信息

image-20240822200528416

常用模块简介

image-20240822200804494

  • pam_securetty.so:限制root只能够从安全(secure)的终端机登录。
  • pam_nologin.so:限制一般用户是否能够登录主机之用。当/etc/nologin这个文件存在,则所有一般用户均无法再登录系统。
  • pam_selinux.so
  • pam_console.so:当系统出现某些问题,或者是某些时刻你需要使用特殊的终端接口登录主机,它可以帮助你处理一些文件权限的问题,让用户通过特殊终端接口顺利登录系统。
  • pam_loginuid.so:验证用户的UID是否真的是我们所需要的数值。
  • pam_env.so:用来设置环境变量的。
  • pam_UNIX.so:可以用于验证阶段的认证功能、可以用于授权阶段的账号许可证管理、可以用于会议阶段的日志文件记录、甚至可以用于密码更新阶段的检验。
  • pam_cracklib.so:可以检验密码的强度,
  • pam_limits.so:为ulimit提供能力。

login的PAM验证机制流程:

  1. 验证阶段(auth):首先会先经过pam_securetty.so判断,如果用户是root,则会参考/etc/seecuretty的设置。接下来经过pam_env.so设置额外的环境变量;再通过pam_UNIX.so检验密码,若通过则好好回报login程序;若不通过则继续往下以pam_succeed_if.so判断UID是否大于500,若小于则回报失败,否则再往下以pam_deny.so拒绝连接。
  2. 授权阶段(account):先以pam_nologin.so判断/etc/nologin是否存在,若存在则不许一般用户登录;接下来以pam_UNIX进行账号管理,再以pam_succeed_if.so判断UID是否大于500,若小于则不记录登录信息。最后以pam_permit.so允许该账号登录。
  3. 密码阶段(password):先以pam_cracklib.so设置密码仅能尝试错误3次;接下来以pam_UNIX.so通过md5,shadow等功能进行密码检验,若通过则回报login程序,若不通过则以pam_deny.so拒绝登录。
  4. 会议阶段(session):先以pam_selinux.so暂时关闭SELinux;使用pam_limits.so设置好用户能够操作的系统资源;登录成功后开始记录相关信息在登录文件中;以pam_loginuid.so设置不同的UID权限;打开pam_selinux.so

image-20240822203421868

image-20240822203445058

其他相关文件

主要都在/etc/security中

limits.conf:ulimit的功能,限制用户资源

image-20240822214719490

/var/log/secure,/var/log/messages:PAM会把任何无法登录或者产生的一些错误记录在里面。

Linux主机上的用户信息传递

查询用户:w,who,last,lastlog

image-20240822214733598

lastlog可以知道每个账号的最近登录时间,它会读取/var/log/lastlog

用户对谈:write,mesg,wall

举例来说,我们的Linux上有user和root两个人在线,可以用write来对话

write 用户账号 [用户所在终端接口]

image-20240822215323080

如果user不想接受信息,但是必须接受root的信息。root可以拒绝接收来自其他用户的信息。

mesg n

# 解开
mesg y

还可以进行广播,所有人都可以接收到信息

wall "your_message"

用户邮件信箱:mail

一般来说,mailbox都会放置在/var/spool/mail里

执行mail username@localhost -s"邮件标题"

image-20240822221310558

可以先用vi将信件内容编辑好,然后再用mail user -s “title” < filename来将文件内容传输。

收信时同样使用mail

image-20240822220953256

image-20240822220908508

可以想象为/var/spool/mail/user为user的信箱,而/home/user/mbox为收信箱

手动新增用户

pwck

检查/etc/passwd这个账号配置文件内的信息,与实际的主文件夹是否存在等信息,呵呵还可以比较/etc/passwd /etc/shhadow的信息是否一致

root@master1:/etc/apt# pwck
user 'lp': directory '/var/spool/lpd' does not exist
user 'news': directory '/var/spool/news' does not exist
user 'uucp': directory '/var/spool/uucp' does not exist
user 'list': directory '/var/list' does not exist
user 'irc': directory '/run/ircd' does not exist
user 'master1': directory '/home/master1' does not exist
pwck: no changes

# 绝大部分账号都是系统账号,没有文件夹正常

用户组检查可以用grpck

pwconv

将/etc/passwd内的账号与密码移动到/etc/shadow中

pwunconv

将/etc/shadow内的密码列数据写回/etc/passwd,并且删除/etc/shadow

chpasswd

可以读入未加密前的密码,并且经过加密后,将加密后的密码写入/etc/shadow中

特殊账号(如纯数字账号)的手工新建

纯数字账号容易引起系统的误解

整个流程:

  1. 先新建所需要的用户组(vi /etc/group)
  2. 将/etc/group与/etc/gshadow同步(grpconv)
  3. 新建账号的各个属性(vi /etc/passwd)
  4. 将/etc/passwd与/etc/shadow同步(pwconv)
  5. 新建该账号的密码(passwd accountname)
  6. 新建用户主文件夹(cp -a /etc/skel /home/accountname)
  7. 更改用户主文件夹的属性(chown -R accounname.group /homr/accountname)
# 手动新增用户

root@master1:/etc/apt# vi /etc/group
root@master1:/etc/apt# grpconv
root@master1:/etc/apt# grep 'yiiong' /etc/group /etc/gshadow
/etc/group:yiiong:x:520:
/etc/gshadow:yiiong:x::
root@master1:/etc/apt# vi /etc/passwd
root@master1:/etc/apt# pwconv
root@master1:/etc/apt# grep 'yiiong' /etc/passwd /etc/shadow
/etc/passwd:yiiong:x:700:520::/home/yiiong:/bin/bash
/etc/shadow:yiiong:x:19957:0:99999:7:::
root@master1:/etc/apt# passwd yiiong
New password:
Retype new password:
passwd: password updated successfully
root@master1:/etc/apt# cp -a /etc/skel /home/yiiong/
root@master1:/etc/apt# chown -R yiiong:yiiong /home/yiiong/
root@master1:/etc/apt# chmod 700 /home/yiiong/

批量新建账号模板(适用于passwd --stdin参数)

image-20240822223820675

批量新建账号的范例(适用于连续数字,如学号)

image-20240822224143476

image-20240822224155845

image-20240822224247354

image-20240822224255169

磁盘配额(Quota)与高级文件系统管理

什么是Quota?

Linux是多用户、多任务的环境,所以会有多用户共同使用一个硬盘空间的情况发生,如果其中少数几个用户占掉了大量的硬盘空间,肯定会影响其他用户的使用。因此管理员应当适当限制硬盘的空间给用户,以妥善分配系统资源。

Quota的一般用途

  • 针对www server,例如每个人的网页空间容量限制
  • 针对mail server,例如每个人的邮件空间限制
  • 针对file server,例如每个人最大的可用网络硬盘空间
  • 限制某一用户组所能使用的最大磁盘配额
  • 限制某一用户的最大磁盘配额
  • 以Link的方式使邮件可以作为限制的配额(更改/var/spool/mail这个路径)

Quota的使用限制

  • 仅能针对整个文件系统:例如你的/dev/sda5是挂载在/home下的,那么/home下面的所有目录都会受到限制
  • 内核必须支持quota

Quota的日志文件

并不是所有Linux上的账号都可以设置Quota,比如root就不行,因为整个系统所有的数据几乎都是它的。

所有你不能针对某个目录来进行Quota的设计,但你可以针对某个文件系统来设置。

Quota的设置选项

Quota针对整个文件系统的限制项目有以下几个部分:

1.容量限制或者文件数量限制(block或者inode)

限制inode用量(管理用户可以新建的文件数量)

限制block用量(管理用户磁盘容量的限制)

也就是说要么限制能创建多少文件,要么限制创建出的文件大小。

2.soft/hard:

hard:表示用户的用量绝对不会超过这个限制

soft:表示用户在低于soft限制时,可以正常使用磁盘,如果超过soft但是低于hard,每次用户登录系统时,系统会主动发出磁盘即将饱满的警告信息,并且还会给予一个宽限时间(gracetime)

3.会倒计时的宽限时间(grace time)

只有在用户的磁盘用量介于soft和hard之间时,才会出现且会倒数的一个时间。一般为7天,如果7天内不进行任何磁盘管理,那么soft会立刻替代hard,从而使用户的磁盘使用权可能会被锁住。

Quota的实践

范例

image-20240830003959463

先创建用户,并加入到用户组中

文件系统支持

先确保/home为独立的文件系统

此外,VFAT文件系统并不支持Liunx Quota功能

image-20240901231706487

如果只想在开机中使用Quota

mount -o remount,usrquota,grpquota /home

image-20240901231757260

如果想开机就能自动挂载的话,可以修改/etc/fstab

vi /etc/fstab
LABEL=/home /home ext4 defaults,usrquota,grpquota 1 2

新建Quota配置文件

Quota是通过分析整个文件系统中每个用户(用户组)拥有的文件总数与总容量,再将这些数据记录在该文件系统的最顶层目录,然后在该配置文件中再使用每个账号(或用户组)的限制值去规定磁盘使用量的。

quotacheck:扫描文件系统并新建Quota配置文件

quotacheck [-avugfM] [/mount_point]

-a:扫描所有在/etc/mtab内,含有quota支持的文件系统。
-u:针对用户扫描文件与目录的使用情况,还会新建aquota.user
-v:显示扫面过程的信息
-f:强制扫描文件系统,并写入新的quota配置文件
-M:强制以读写的方式扫描文件系统,只有在特殊情况下才会使用。

image-20240901233812537

Quota的启动、关闭于限制值设置

quotaon:启动quota服务

-u:针对用户启动(aquota.user)
-g:用户组
-v:显示启动过程
-a:根据/etc/mtab内的文件系统设置有关的quota,不加的话后面要加上特定的文件系统

只需要启动一次就好,下次启动系统会自动启动quota

image-20240901234616146

quotaoff:关闭quota服务

edquota:编辑账号/用户组的限值与宽限时间

image-20240901234811368

限制myquota1,然后以1为模板限制后面的用户,然后再限制用户组,最后设置宽限时间为14天

image-20240901235153713

image-20240901235510163

Quota限制值的报表

quota的报表有两种模式

  1. 针对每个个人或用户组的quota命令
  2. 针对整个文件系统的repquota命令

quota:单一用户的quota报表

image-20240901235815287

image-20240901235909145

相比于edquota多了一个grace

repquota:针对文件系统的限额做报表

image-20240902000219825

image-20240902000326954

root 用户没有设置配额限制。
用户 myquota1 至 myquota5 每人都有一个软限制为 245MB 和硬限制为 293MB 的磁盘空间。目前这些用户都没有使用任何磁盘空间。
每个用户的文件数量都还没有使用,软硬限制也都未设置。
统计数据显示总共有 7 个块,其中 1 个块是数据块。有 6 个用户被报告,并且使用的平均值为 6.000000,这个值通常是指每个用户使用的平均块数

测试与管理

image-20240902003829462

warnquota:对超过限额者发出警告信

setquota:直接于命令中设置quota限额

image-20240902004333722

不改动既有系统的Quota实例

link的使用

image-20240902004507818

软件磁盘阵列(Software RAID)

磁盘阵列全名RedundantArrays of Inexpensive Disks(RAID),即容错廉价磁盘阵列。

它可以通过一些技术,将多个较小的磁盘整合成为一个较大的磁盘设备,而这个较大的磁盘不仅可以存储,还具有数据保护的功能。

整个RAID有几个等级,使得整合后的磁盘具有不同的功能。

RAID-0(等量模式,stripe):性能最佳

该模式如果使用相同型号相同容量的磁盘来组成,效果最佳。

RAID-0会将磁盘先切出等量的区块(chunk),然后当一个文件要写入RAID时,该文件会依据块的大小切割好,之后再依序放到各个磁盘里去。由于每个磁盘会交错存放数据,因此当你的数据要写入RAID时,数据会被等量放置在各个磁盘上面。

举例来说,你有两块磁盘组成RAID-0,当你有100MB的数据要写入时,每个磁盘会各自被分配50MB的存储量。

因为数据被分散到了不同的磁盘上, 每块磁盘负责的数据量就低了。所以说,越多块磁盘组成RAID-0,性能会越好,因为每块磁盘负责数据量就更低了。

但是RAID-0需要自行负担数据损毁的风险,只要任何一块出问题,整个数据都会无法读取。因为文件数据被切割,按序放在各个磁盘上,一旦有一个磁盘出问题,文件数据就会缺一块。

假如200GB和500GB组成RAID-0,那最初的400GB是分散在两块磁盘上的,后面再加入的数据就只能存放在500GB的硬盘上了。

RAID-1(映像模式,mirror):完整备份

也需要相同的磁盘容量,最好是一模一样的硬盘。

这种模式主要是让同一份数据完整的保存在两块磁盘上面。比如100MB的数据保存在RAID-1组成的两块磁盘上时,这两块磁盘会同步写入这100MB的数据。因此整体的容量几乎少了一半。

因为数据进入RAID-1后会被分成两股,并分别写入到各个磁盘里。因此在大量写入RAID-1的情况下,写入的额性能可能会变得很差。

好在如果你使用了硬件RAID卡,磁盘阵列卡会主动复制一份而不使用系统的I/O系统,性能还可以。

RAID-1最大的优点就是数据的备份,但是总容量是全部磁盘容量的一半。虽然RAID-1的写入性能不佳,但是它的读取能力还可以,因为RAID-1会自行取得最佳的读取平衡。

RAID 0 + 1, RAID 1 + 0

所谓的RAID 0 + 1,意思就是先让两块磁盘组成RAID-0,这样的设置共有两组,然后这两组RAID-0再组成RAID-1。

当有100MB的文件写入时,由于RAID-1的原因会被复制两份,一份给A和B,另一份给C和D。然后A和B又因为RAID-0,对数据切割并且按序排放。

RAID-5:性能与数据备份的均衡考虑

至少需要三块以上的硬盘。

RAID-5的写入有点类似RAID-0,但是每个循环的写入过程中,在每块磁盘上还加入一个同位检查数据(Parity),这个数据会记录其他磁盘的备份数据,用于数据恢复。

image-20240903001749967

任何一个磁盘损毁时都能够通过其他磁盘的检查码来重建原本磁盘内的数据。不过要注意的是由于同位检查码,因此RAID-5的总容量会是整体磁盘数量减一块。RAID-5仅能支持一块磁盘损毁的情况。

RAID-5由于要计算同位检查码,所以写入性能不佳。依赖硬件。

Spare Disk:预备磁盘功能

当磁盘阵列的磁盘损毁时,需要将坏硬盘拔掉,再插入新硬盘。换完且顺利启动磁盘阵列后,磁盘阵列就会开始主动重建原本坏掉的那块磁盘数据到新的磁盘上。

Spare Disk可以让我们实时的在坏掉硬盘时主动重建。所谓的Spare Disk就是把一块或多块没有包含在原本磁盘阵列等级中的磁盘,当磁盘阵列有磁盘损毁时,Spare Disk会被主动拉入磁盘阵列,坏掉的磁盘会被主动踢出,然后重建系统。

software,hardware RAID

硬件磁盘阵列依靠磁盘阵列卡,但是卡太贵。

软件磁盘阵列依靠CPU的运算与I/O总线的资源。

CentOS通过mdadm这套软件,可以让分区组成RAID。

软件磁盘阵列的设置

mdadm --create --auto=yes /dev/md[0-9] --raid-devices=N \
> --level=[015] --spare-devices=N /dev/sda[1,2,3......]

--create:新建raid参数
--auto=yes:决定新建后面接的软件磁盘阵列设备,例如/dev/md0
--raid-devices=N:使用几个磁盘作为磁盘阵列
--spare-devices=N:做备用设备
--level=[015]:磁盘阵列等级
--detail:后面所接磁盘阵列设备的详细信息

以madam创建raid

mdadm --create --auto=yes /dev/md0 --level=5 --raid-devices=4 --spare-deevices=1 /dev/sdb[1-5]

image-20240907231242244

第一行:指出md0为raid5,使用了sdb[1-4]四块磁盘,每个磁盘[]内的数字为此磁盘在RAID中的额顺序,sdb5的(S)意思是它为spare

第二行:此磁盘阵列有608256个blocks(每个blocks为1kb),使用RAID 5,写入磁盘的小区块为512K,使用algorithm2磁盘阵列算法。

[m/n]代表此数组需要m个设备,且n个设备正常运行。U代表正常运作,4个U代表四个设备正常运行。

仿真RAID错误的救援模式

mdadm --manage /dev/md[0-9] [--add 设备] [--remove 设备] \
> [--fail 设备]
--fail:会将后面的设备设置为出错的状态

设置某个设备出错

mdadm --manage /dev/md0 --fail /dev/sdb3

然后raid-5就会立刻将spare-device拉入raid组恢复正常

开机自启动RAID并自动挂载

利用uuid

image-20240908204044731

关闭软件RAID

umount /dev/md0
修改/etc/fstab,关闭开机自动挂载
mdadm --stop /dev/md0
cat /proc/mdstat # 查看状态
修改/etc/mdadm.conf # 取消设置
删除分区上的 RAID 超级块信息,使得这些设备不再被认为是 RAID 的一部分。
mdadm --zero-superblock /dev/sdb1

逻辑卷管理器(Logical Volume Manager)

image-20240922230749604

LVM的重点在于可以弹性调整文件系统的容量,它可以整个多个物理分区在一起,让这些分区看起来就像是一个磁盘一样。

什么是LVM:PV、PE、VG、LV的意义

LVM的做法是将几个物理的分区(或磁盘)通过软件组合成为一块看起来是独立的大磁盘(VG),然后将这块大磁盘再经过分成为可用分区(LV),最终就能挂载使用了。

PV(物理卷):PhysicalVolume

我们实际的分区需要调整系统标识符(system ID)成为8e(LVM的标识符),然后再经过pvcreate的命令将它转为LVM最底层的物理卷(PV),之后才能够将这些PV加以利用,调整system ID的方式就是fdisk

VG(卷用户组):Volume Group

VG就是LVM组合成为的大磁盘。VG的大小与PE有关。

PE(物理扩展块):Physical Extend

LVM默认使用4MB的PE块,而LVM的VG最多仅能含有65534个PE,因此默认的LVM VG会有256G.

PE是整个LVM最小的存储块,也就是说,我们的文件数据都是由写入PE来处理的。类似于文件系统中的block

LV(逻辑卷):Logical Volume

最终的VG还会被切割成为LV,这个LV就是最后可以被格式化使用的类似分区。其大小与LV内的PE有关。

LV的设备文件通常指定为/dev/vgname/lvname

LVM通过交换PE来进行数据转换,将原本LV内的PE移转到其他设备中以降低LV容量。

image-20240908224033407

VG内的PE会分给虚拟的LV,如果VG要扩充,加上其他的PV即可。LV要扩充的话,加入VG中没有使用的PE。

实现流程

image-20240908224402222

数据写入LV时,写入硬盘有两种方式

  1. 线性模式(linear):假如将/dev/hda1、/dev/hda2加入VG,并且整个VG只有一个LV时,所谓线性模式就是/dev/hda1用完后,再用/dev/hda2
  2. 交错模式(triped):将一个数据分成两部分,分别写入两个分区,类似于RAID-0

LVM最主要的用途是弹性调整文件系统的容量,而不是着眼在性能上。如果强调性能与备份,那么直接使用RAID即可。

LVM实作流程

步骤:

  1. 分出5个分区,设置Type为Linux LVM

    fdisk /dev/sdb
    使用t

    image-20240908230935910

  2. 全部的分区整合为1个VG,VG名称设置为myvg,PE大小为16MB

  3. 全部VG容量都丢给LV,LV名称设置为mylv

  4. 最终LV格式化为ext4,挂载在/mnt/lvm

PV阶段
  • pvcreate:将物理分区新建成为PV
  • pvscan:查询目前系统里面任何具有PV的磁盘
  • pvdisplay:显示出目前系统上面的PV状态
  • pvremove:将PV属性删除,让该分区不具有PV属性

image-20240908233743388

pvscan回显的最后一行,显示:整体PV的量 / 已经使用VG的PV量 / 剩余PV量

Allocatable:是否已经被分配

VG阶段
  • vgcreate:新建VG
  • vgscan:查找系统上面是否有VG
  • vgdisplay:显示目前系统上面VG的状态
  • vgextend:在VG内增加额外的PV
  • vgreduce:在VG内删除PV
  • vgchange:设置VG是否启动
  • vgremove:删除一个VG
vgcreate [-s N[mgt]] VG名称 PV名称

-s:后面接PE的大小

image-20240909220909232

image-20240909221312672

sdb5没有用,此时扩容VG

vgeextend myvg /dev/sdb5

image-20240909221056926

image-20240909221109661

LV阶段

创造出VG后,接下来就要新建分区。这个分区就是LV。

假设要将刚才那个myvg磁盘分成mylv,整个VG的容量都被分配到mylv里面。

命令和vg的一样,多了lvresize:对LV进行容量大小的调整

lvcreate [-L N[mgt]] [-n LV名称] VG名称
lvcreate [-l N] [-N lV名称] VG名称

-L:后面接容量,最小单位是PE。因此这个数量必须是PE的倍数
-l:后面接PE的个数,而不是数量。
-n:后面接LV的名称

把myvg全部的PE分给mglv

image-20240909223526496

创建好的LV的信息,此时LV的名称为/dev/myvg/mylv

image-20240909223559288

放大LV容量
  1. 用fdisk 设置新的具有8e systemID的分区
  2. 利用pvcreate构建PV
  3. 利用vgextend将PV加入我们的myvg
  4. 利用lvresize将新加入的PV内的PE加入mylv
  5. 通过resize2fs将文件系统的容量确实增加

因为文件系统格式化的时候新建是多个block group,因此我们可以通过在文件系统当中增加block group的方式来增减文件系统的量,而增减block group就是利用resize2fs

新建新的PV

image-20240911163716964

使用vgextend加大VG

image-20240911163833230

可以看到PE从之前的48增加到92

利用lvresize放大LV,将剩余的31个PE加入LV

image-20240911164116875

LV被放大到1.44G左右,但是文件系统却没有增加(大约0.96G)

image-20240911164703938

使用resize2fs处理文件系统

resize2fs [-f] [devices] [size]

-f:强制resize

完整地将LV的容量扩充到整个文件系统

image-20240913192515324

当使用 lvextend 命令扩展逻辑卷时,实际上只是增加了逻辑卷的大小,但这并不会自动扩展文件系统。文件系统不知道逻辑卷已经被扩展,因此它仍然认为自己的大小没有变化。所以需要使用resize2fs来扩充文件系统的大小。

缩小LV容量

先缩小文件系统

image-20240913193253943

然后将LV缩小

使用lvresize

image-20240913193503605
image-20240913193517128

接下来将/dev/sdc1移出myvg这个VG中,所以需要先确定/dev/sdc1里面的PE完全不被使用后才能将其抽离。

pvremove /dev/sdc1

LVM的系统快照(snapshot)

image-20240922215101082

LVM会预留一个区域作为数据存放处。快照区与系统区共享所有的PE数据,因此快照区的内容与文件系统是一模一样的。等系统运行一段时候后,假设A区域的数据被改动了,则改动前的系统会将该区域的数据移动到快照区。

快照区如何创建?首先由于快照区与原来的LV共享很多PE区块,因此快照与被快照的LV必须在同一个VG上面。

快照区的创建

使用lvcreate创建系统快照区,给予20个PE

-s表示创建快照的意思

-n后面接快照区的设备名称

-l接PE的数量来作为快照区

image-20240922220005769

20240922-220414

快照的工作原理是使用一种称为“写时复制”(Copy-on-Write, COW)的技术。作用是在某一时刻捕获原卷的状态,以便你可以在这个时间点恢复数据或进行备份。

此时挂载/dev/vg/myss到/mnt/ss和/dev/vg/lv到/mnt/lvm,发现两个数据一模一样

image-20240922221011979

利用快照复原系统

要注意的是要复原的数据不能高于快照区所能负载的实际容量

image-20240922221244750

此时我们删除/mnt/lvm/lost+found,然后利用/mnt/myss/进行复原

image-20240922221406294

可以看到快照区已经被使用了10%,因为原始的文件系统被改动过

20240922-221705

利用快照区进行复原

image-20240922223410866

复原的过程有些特别。需要先进行备份,

为什么不可以直接格式化/dev/vg/lv,然后将/dev/vg/myss直接复制给lv呢?

因为myss是lv的快照,快照卷主要用于存储原卷数据的变化,而不是完整的数据副本。

1.快照卷中的数据块引用的是原卷在创建快照时的状态,但这些状态已经不存在了,因为原卷的数据已经被新的文件系统覆盖。

2.如果你格式化整个lv时,原本的文件系统所有数据就会被移动到ss。如果ss的容量不够大,那么这部分的数据将无法复制到ss内,数据也会无法复原。

tar -jcv -f /bak/lvm.tar.bz2 *
-j表示使用bzip2进行压缩
-c归档
# 将快照区删除
umount /mnt/ss
lvremove /dev/vg/myss

umount /mnt/lvm
mkfs -t ext4 /dev/vg/lv
mount /dev/vg/lv /mnt/lvm
tar -jxv -f /bak/lvm.tar.bz2 -C /mnt/lvm
# 此时/mnt/lvm就还原了

LVM的关闭

  1. 先卸载所有系统上面的LVM文件系统(包括快照和所有的LV)
  2. 使用lvremove删除LV
  3. 使用vgchange -an VGname 让VGname这个VG不具有Active的标志
  4. 使用vgremove删除VG
  5. 使用pvremove删除PV
  6. 最后使用fdisk将ID修改回来

例行性工作(corntab)

特性 Cron Systemd
设计理念 定时任务调度 系统和服务管理
配置方式 crontab 文件,五字段语法 .timer 和 .service 单元文件,灵活的时间表达
适用场景 简单任务,用户级任务 复杂任务,系统级任务
用户管理 每个用户可以有自己的 crontab 系统级别的任务管理
持久性 不支持持久性任务 支持持久性任务
依赖管理 有限的依赖管理 强大的依赖管理
日志管理 依赖系统日志或自定义日志 集成的日志管理