Linux文本处理工具和Shell编程基础

一、Linux文本处理工具

grep:命令主要对文本的(正则表达式)行基于模式进行过滤
sed:stream editor,文本编辑工具
awk:Linux上的实现gawk,文本报告生成器

文本处理三剑客之grep

grep:Global search REgular expression and Print out the line
作用:文本搜索工具,根据用户指定的 “模式” 对目标文本逐行进行匹配检查;打印匹配到的行
模式:由正则表达式字符及文本字符所编写的过滤条件

帮助:

https://man7.org/linux/man-pages/man1/grep.1.html

格式:

grep [OPTIONS...] PATTERN [FILE...]
#常见选项:
-E|--extended-regexp #使用ERE,相当于egrep
-F|--fixed-strings #不支持正则表达式,相当于fgrep
-G|--basic-regexp #将样式视为普通的表示法来使用
-P|--perl-regexp #支持Perl格式的正则表达式
-e|--regexp=PATTERN #实现多个选项间的逻辑or关系,如:grep –e ‘cat ' -e ‘dog'
file
-f|--file=FILE #从文件中读取匹配规则,每行一条
-i|--ignore-case #忽略字符大小写
-w|--word-regexp #匹配整个单词
-x|--line-regexp #整行匹配
-s|--no-messages #不显示错误信息
-v|--invert-match #显示没有被匹配上的行,即取反
-B|--before-context=N #显示匹配到的字符串所在的行及其前N行
-A|--after-context=N #显示匹配到的字符串所在的行及其后n行
-C|--context=N #显示匹配到的字符串所在的行及其前后各N行
-N #同 --context=N
--color=auto #对匹配到的内容高亮显示[always|never|auto]
-m|--max-count=N #只匹配N行,是行,不是次数,一行可能匹配两个,但是,这里是行
-b|--byte-offset #显示匹配行第一个字符的编号
-n|--line-number #显示匹配的行号
-H|--with-filename #显示匹配行所在的文件名
-h|--no-filename #不显示匹配行所在的文件名
-o|--only-matching #仅显示匹配到的字符串
-q|--quiet|--silent #静默模式,不输出任何信息,结果要从变量$?拿
--binary-files=TYPE #指定二进制文件类型 [binary|text|without-match]
-a|--text #同 --binary-files=text
-I #同 --binary-files=without-match
-d|--directories=ACTION #怎样查找目录 [read|recurse|skip]
-D|--devices=ACTION #怎样查找设备文件 [read|skip]
-r|--recursive #递归目录,但不处理软链接
-R|--dereference-recursive #递归目录,但处理软链接
-L|--files-without-match #显示没有匹配上的文件名,只显示文件名
-l|--files-with-matches #显示匹配上的文件名,只显示文件名
-c|--count #统计匹配的行数,是行数,一行可以匹配一次到多次

 范例:

#处理文件
[root@ubuntu2204 ~]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
#管道
[root@ubuntu2204 ~]# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
#标准输入重定向
[root@ubuntu2204 ~]# grep root < /etc/passwd
root:x:0:0:root:/root:/bin/bash
#取前三行
[root@ubuntu2204 ~]# grep -m 3 bin /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
#取反,取不匹配的行
[root@ubuntu2204 ~]# grep -v nologin /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
pollinate:x:105:1::/var/cache/pollinate:/bin/false
#不看注释行
[root@ubuntu2204 ~]# grep -v "#" /etc/fstab
#不区分大小写
[root@ubuntu2204 ~]# grep -i ROOt /etc/passwd
root:x:0:0:root:/root:/bin/bash
#显示行号
[root@ubuntu2204 ~]# grep -n bash /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
32:mage:x:1000:1000:mage:/home/mage:/bin/bash
34:jose:x:1001:1001::/home/jose:/bin/bash
35:tom:x:1002:1002::/home/tom:/bin/bash
36:jerry:x:1003:1003::/home/jerry:/bin/bash
#显示匹配的行数
[root@ubuntu2204 ~]# grep -c bash /etc/passwd
5
#仅显示匹配到的内容
[root@ubuntu2204 ~]# grep -o root /etc/passwd
root
root
root
#静默模式
[root@ubuntu2204 ~]# grep -q root /etc/passwd
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# grep -q roooot /etc/passwd
[root@ubuntu2204 ~]# echo $?
1
#显示匹配到的行及后两行
[root@rocky86 ~]# grep -A 2 root /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
#显示匹配到的行及前两行
[root@rocky86 ~]# grep -B 2 root /etc/passwd
root:x:0:0:root:/root:/bin/bash
--
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
#显示匹配到的行及前后各两行
[root@rocky86 ~]# grep -C 2 root /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
#显示匹配root的行或匹配bash的行
[root@ubuntu2204 ~]# grep -e root -e bash /etc/passwd
root:x:0:0:root:/root:/bin/bash
mage:x:1000:1000:mage:/home/mage:/bin/bash
jose:x:1001:1001::/home/jose:/bin/bash
tom:x:1002:1002::/home/tom:/bin/bash
jerry:x:1003:1003::/home/jerry:/bin/bash
#显示匹配root的行且匹配bash的行
[root@ubuntu2204 ~]# grep root /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
#从文件读取匹配规则
[root@ubuntu2204 ~]# cat test.txt
root
bash
[root@ubuntu2204 ~]# grep -f test.txt /etc/passwd
root:x:0:0:root:/root:/bin/bash
mage:x:1000:1000:mage:/home/mage:/bin/bash
jose:x:1001:1001::/home/jose:/bin/bash
tom:x:1002:1002::/home/tom:/bin/bash
jerry:x:1003:1003::/home/jerry:/bin/bash
#递归匹配
#不处理链接
[root@ubuntu2204 ~]# grep -r root /etc/*
#处理链接
[root@ubuntu2204 ~]# grep -R root /etc/*
#只显示有匹配到的文件的文件名,不显示具体内容
[root@ubuntu2204 ~]# grep root -l /etc/passwd /etc/sudoers /etc/my.cnf
/etc/issue
/etc/passwd
/etc/sudoers
grep: /etc/my.cnf: No such file or directory
#显示内容来自于哪个文件
[root@ubuntu2204 ~]# grep -H root /etc/passwd /etc/sudoers /etc/my.cnf
/etc/issue
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/sudoers:# This file MUST be edited with the 'visudo' command as root.
/etc/sudoers:# This preserves proxy settings from user environments of root
/etc/sudoers:# While you shouldn't normally run git as root, you need to with
etckeeper
/etc/sudoers:# Per-user preferences; root won't have sensible values for them.
/etc/sudoers:root ALL=(ALL:ALL) ALL
/etc/sudoers:# Members of the admin group may gain root privileges
grep: /etc/my.cnf: No such file or directory
#命令行展开
[root@ubuntu2204 ~]# grep `whoami` /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu2204 ~]# grep $(whoami) /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu2204 ~]# echo Linux123 | grep $(uname)
Linux123
#变量展开
[root@ubuntu2204 ~]# grep "$USER" /etc/passwd
root:x:0:0:root:/root:/bin/bash
#取CPU核数
[root@ubuntu2204 ~]# grep -c processor /proc/cpuinfo
2
#分区利用率最大的值
[root@ubuntu2204 ~]# df | grep '^/dev/sd' |tr -s ' ' %|cut -d% -f5|sort -n|tail
-1
14
[root@ubuntu2204 ~]# df |grep '^/dev/sd' |grep -oE '\<[0-9]{,3}%'|tr -d '%'|sort
-nr|head -n1
14
[root@ubuntu2204 ~]# df |grep '^/dev/sd' |grep -oE '\<[0-9]{,3}%'|grep -Eo '[0-
9]+' |sort -nr|head -n1
14
#哪个IP和当前主机连接数最多的前三位
[root@rocky86 ~]# ss -nt | grep "^ESTAB" |tr -s ' ' : |cut -d: -f6|sort |uniq -c|sort -nr|head -n3
     11 1.49.174.161
      9 83.220.108.173
      7 123.57.75.69
#连接状态的统计
[root@rocky86 ~]# ss -nta | grep -v '^State' |cut -d" " -f1|sort |uniq -c
      2 CLOSE-WAIT
      1 CLOSING
     81 ESTAB
      2 FIN-WAIT-1
      5 LAST-ACK
      5 LISTEN
      2 SYN-RECV
   2372 TIME-WAIT
[root@rocky86 ~]# ss -nta | tail -n +2 |cut -d" " -f1|sort |uniq -c
      2 CLOSE-WAIT
      2 CLOSING
     75 ESTAB
      1 FIN-WAIT-1
      3 LAST-ACK
      5 LISTEN
      1 SYN-RECV
   3187 TIME-WAIT

[root@ubuntu2204 ~]# grep -v "^#" /etc/profile | grep -v '^$'
[root@ubuntu2204 ~]# grep -v "^#\|^$" /etc/profile
[root@ubuntu2204 ~]# grep -v "^\(#\|$\)" /etc/profile
[root@ubuntu2204 ~]# grep -Ev "^(#|$)" /etc/profile
[root@ubuntu2204 ~]# egrep -v "^(#|$)" /etc/profile

[root@centos8 ~]#grep -o 'r..t' /etc/passwd
root
root
root
root
r/ft
rypt

[root@ubuntu2204 ~]# ifconfig | grep -E '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]
{1,3}'
inet 10.0.0.206 netmask 255.255.255.0 broadcast 10.0.0.255
RX packets 16993 bytes 3820791 (3.8 MB)
TX packets 15194 bytes 3563956 (3.5 MB)
inet 127.0.0.1 netmask 255.0.0.0
[root@ubuntu2204 ~]# ifconfig | grep -E '([0-9]{1,3}.){3}[0-9]{1,3}'
inet 10.0.0.206 netmask 255.255.255.0 broadcast 10.0.0.255
RX packets 17025 bytes 3823233 (3.8 MB)
TX packets 15223 bytes 3567976 (3.5 MB)
inet 127.0.0.1 netmask 255.0.0.0
[root@ubuntu2204 ~]# ifconfig ens33 | grep -Eo '([0-9]{1,3}\.){3}[0-9]
{1,3}'|head -1
10.0.0.206
[root@ubuntu2204 ~]# cat reg.txt
([0-9]{1,3}\.){3}[0-9]{1,3}
[root@ubuntu2204 ~]# ifconfig | grep -oEf reg.txt
10.0.0.206
255.255.255.0
10.0.0.255
127.0.0.1
255.0.0.0

[root@ubuntu2204 ~]# grep -E 'root|bash' /etc/passwd
root:x:0:0:root:/root:/bin/bash
mage:x:1000:1000:mage:/home/mage:/bin/bash
jose:x:1001:1001::/home/jose:/bin/bash
tom:x:1002:1002::/home/tom:/bin/bash
jerry:x:1003:1003::/home/jerry:/bin/bash
[root@ubuntu2204 ~]# grep -e 'root' -e 'bash' /etc/passwd
root:x:0:0:root:/root:/bin/bash
mage:x:1000:1000:mage:/home/mage:/bin/bash
jose:x:1001:1001::/home/jose:/bin/bash
tom:x:1002:1002::/home/tom:/bin/bash
jerry:x:1003:1003::/home/jerry:/bin/bash

[root@ubuntu2204 ~]# grep -w root /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu2204 ~]# grep '\<root\>' /etc/passwd
root:x:0:0:root:/root:/bin/bash

[root@centos8 ~]#grep "^\(.*\)\>.*\<\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
bash:x:1008:1008::/home/bash:/bin/bash
nologin:x:1011:1011::/home/nologin:/sbin/nologin
[root@centos8 ~]#grep -E "^(.*)\>.*\<\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
bash:x:1008:1008::/home/bash:/bin/bash
nologin:x:1011:1011::/home/nologin:/sbin/nologin
[root@centos8 ~]#egrep "^(.*)\>.*\<\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
bash:x:1008:1008::/home/bash:/bin/bash
nologin:x:1011:1011::/home/nologin:/sbin/nologin

#过滤掉文件的注释(包括#号的行)和空行
[root@centos8 ~]#grep -Ev '^$|#' /etc/fstab
UUID=01f1068e-6937-4fb2-b64b-0d7d6b85ad08 / xfs defaults 0
0
UUID=cb21e5ce-edf6-4ed1-8df9-ba98520a68dc /boot xfs defaults 0
0
UUID=9ea3524a-7cff-49a0-951e-8429a30bd0a0 /data xfs defaults 0
0
UUID=42174d44-41aa-448b-88bc-fd36d6a49e39 swap swap defaults 0
0

#算出所有人的年龄总和
[root@ubuntu2204 ~]# cat age.txt
xiaoming=20
xiaohong=18
xiaoqiang=22
[root@ubuntu2204 ~]# cut -d"=" -f2 age.txt|tr '\n' + | grep -Eo ".*[0-9]"|bc
60
[root@ubuntu2204 ~]# grep -Eo "[0-9]+" age.txt | tr '\n' + | grep -Eo ".*[0-
9]"|bc
60
[root@ubuntu2204 ~]# grep -oE '[0-9]+' age.txt| paste -s -d+|bc
60

 文本处理三剑客之sed

sed 即 Stream EDitor,和 vi 不同,sed是行编辑器
相关文档:

http://sed.sourceforge.net/
https://man7.org/linux/man-pages/man1/sed.1.html
http://www.gnu.org/software/sed/manual/sed.html

基本用法

格式: 

sed [OPTION]... {script-only-if-no-other-script} [input-file]...
#常用选项
-n|--quiet|--silent #不输出模式空间内容到屏幕,即不自动打印
-e script|--expression=script #多个script,or 的关系
-f script-file|--file=script-file #从指定文件中读取编辑脚本
-i[SUFFIX]|--in-place[=SUFFIX] #-i 直接修改文件,-i.bak 以.bak后缀
备份原文件
-c|--copy #配合i一起使用,保留原文件
-l N|--line-length=N #指定每行长度,如果过长,就拆分成多行,
要加 `l'
--posix #禁用GNU扩展
-E|-r|--regexp-extended #扩展正则表达式
-s|--separate #将多个文件视为独立文件,而不是单个连续
的长文件流
-ir #此组合不支持
-ri #支持
-i -r #支持
-ni #此组合危险,会清空文件

script格式:

'AddrCmd' #地址命令 在哪些行,执行什么操作

 地址格式:

#为空,则表示对全文进行处理
#单地址,指定行
N #具体行号
$ #最后一行
/pattern/ #能被匹配到的每一行
#范围地址
M,N #第M行到第N行
M,+N #第M行到第M+N行 3,+4 表示从第3行到第7行
/pattern1/,/pattern2/ #从第一个匹配行开始,到第二个匹配行中间的行
M,/pattern/ #行号开始,匹配结束
/pattern/,N #匹配开始,行号结束
#步长
1~2 #奇数行
2~2 #偶数行

命令:

p #打印当前模式空间内容,追加到默认输出之后
Ip #忽略大小写输出
d #删除模式空间匹配的行,并立即启用下一轮循环
a [\]text #在指定行后面追加文本,支持使用\n实现多行追加
i [\]text #在行前面插入文本
c [\]text #替换行为单行或多行文本
w file #保存模式匹配的行至指定文件
r file #读取指定文件的文本至模式空间中匹配到的行后
= #为模式空间中的行打印行号
! #模式空间中匹配行取反处理
q #结束或退出sed

查找替代:

s/pattern/replace/修饰符 #查找替换,支持使用其它分隔符,可以是其它形式:s@@@,s###
#修饰符
g #行内全局替换
p #显示替换成功的行
w file #将替换成功的行保存至文件中
I|i #忽略大小写
#后向引用
\1 #第一个分组
\2 #第二个分组
\N #第N个分组
& #所有搜索内容

范例:

#等待标准输入,script为空,默认是直接输出
[root@ubuntu2204 ~]# sed ''
123
123
[root@ubuntu2204 ~]# sed '' -
123
123
#script为空,默认输出内容
[root@ubuntu2204 ~]# sed '' /etc/issue
Ubuntu 22.04 LTS \n \l
#script 中执行p命令,再加上默认输出,所有每行都显示了两次
[root@ubuntu2204 ~]# sed 'p' /etc/issue
Ubuntu 22.04 LTS \n \l
Ubuntu 22.04 LTS \n \l
#关闭默认输出,script 为空,则无任何输出
[root@ubuntu2204 ~]# sed -n '' /etc/issue
[root@ubuntu2204 ~]#
#用 -n 选项关闭默认输出,script 中执行p命令
[root@ubuntu2204 ~]# sed -n 'p' /etc/issue
Ubuntu 22.04 LTS \n \l
#输出第一行
[root@ubuntu2204 ~]# sed -n '1p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
#输出最后一行
[root@ubuntu2204 ~]# sed -n '$p' /etc/passwd
jerry:x:1003:1003::/home/jerry:/bin/bash
#正则匹配,输出包含root的行
[root@rocky86 ~]# sed -n '/root/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
#正则匹配,输出以root开头的行
[root@rocky86 ~]# sed -n '/^root/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
#正则匹配,输出以bash结尾的行
[root@rocky86 ~]# sed -n '/bash$/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
jose:x:1010:1010::/home/jose:/bin/bash
jerry:x:1011:1011::/home/jerry:/bin/bash
#正则匹配,显示注释行行号
[root@rocky86 0723]# sed -n '/^#/=' /etc/fstab
2 3 4 #
行号开始,正则结束
[root@rocky86 0723]# sed -n '8,/root/p' /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

范例:添加内容

[root@ubuntu2204 ~]# cat test.txt
aaa
bbb
ccc
bbb
#匹配行后插入
[root@ubuntu2204 ~]# sed '/bbb/a\---' test.txt
aaa
bbb
---
ccc
bbb
---
#指定行前插入
[root@ubuntu2204 ~]# sed '2i\---' test.txt
aaa
---
bbb
ccc
bbb
[root@ubuntu2204 ~]# sed '2,4i\---' test.txt
aaa
---
bbb
---
ccc
---
bbb
#替换,第一行替换成 ---
[root@ubuntu2204 ~]# sed "1c\---" test.txt
---
bbb
ccc
bbb
#替换,第一行替换成两行
[root@ubuntu2204 ~]# sed "1c\---\n+++" test.txt
---
+++
bbb
ccc
bbb
#替换,多行替换成一行
[root@ubuntu2204 ~]# sed "1,2c\---" test.txt
---
ccc
bbb
# \ 的作用
[root@ubuntu2204 ~]# sed '2a *******' test.txt
aaa
bbb
*******
ccc
bbb
[root@ubuntu2204 ~]# sed '2a\ *******' test.txt
aaa
bbb
*******
ccc
bbb

范例:

#取IP行
[root@ubuntu2204 ~]# ifconfig ens33 | head -n 2 | tail -n 1
inet 10.0.0.206 netmask 255.255.255.0 broadcast 10.0.0.255
[root@ubuntu2204 ~]# ifconfig ens33 | sed -n '2p'
inet 10.0.0.206 netmask 255.255.255.0 broadcast 10.0.0.255
[root@ubuntu2204 ~]# ifconfig ens33 | sed -n '/netmask/p'
inet 10.0.0.206 netmask 255.255.255.0 broadcast 10.0.0.255
#命令展开
[root@ubuntu2204 ~]# sed -n "/$(whoami)/p" /etc/passwd
root:x:0:0:root:/root:/bin/bash
#第1行
[root@ubuntu2204 ~]# sed -n "$[$(id -u)+1]p" /etc/passwd
root:x:0:0:root:/root:/bin/bash
#倒数第2行
[root@ubuntu2204 ~]# sed -n "$(echo $[`cat /etc/passwd|wc -l`-1])p" /etc/passwd
jerry:x:1011:1011::/home/jerry:/bin/bash
#变量展开
[root@ubuntu2204 ~]# sed -n "/$USER/p" /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu2204 ~]# number=1;sed -n "${number}p" /etc/passwd
root:x:0:0:root:/root:/bin/bash
#变量和命令
[root@ubuntu2204 ~]# sed -n "$(echo $UID+1|bc)p" /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu2204 ~]# sed -n "$(echo $UID+1|bc),$(echo $UID+3|bc)p" /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

[root@ubuntu2204 ~]# df | sed -n '/^\/dev\/sd/p'
/dev/sda2 1992552 255260 1616052 14% /boot

[root@ubuntu2204 ~]# seq 10 | sed -n '2,4p'
2 
3 
4
[root@ubuntu2204 ~]# seq 10 | sed -n '2,+4p'
2 
3 
4 
5
[root@ubuntu2204 ~]# seq 10 | sed -n '8,$p'
8 
9
10
[root@ubuntu2204 ~]# seq 10 |sed -n '1~2p'
1
3
5
7
9
[root@ubuntu2204 ~]# seq 10 |sed -n '2~2p'
2 
4 
6 
8
10
#删除奇数行
[root@ubuntu2204 ~]# seq 10 |sed '1~2d'
2 
4 
6 
8
10
#删除偶数行
[root@ubuntu2204 ~]# seq 10 |sed '2~2d'
1 
3 
5 
7 
9 
#或
[root@ubuntu2204 ~]# #sed -e '2d' -e '4d' seq.log
1 
3 
5 
6 
7 
8 
9
10
#多个script 写在一起
[root@ubuntu2204 ~]# sed '2d;4d' seq.log
1 
3 
5 
6 
7 
8 
9
10
#只显示非#开头的行
[root@ubuntu2204 ~]# sed -n '/^#/!p' /etc/fstab

#不显示注释行和空行
[root@ubuntu2204 ~]# sed '/^$/d;/^#/d' fstab
[root@ubuntu2204 ~]# sed -En '/^(#|$)/!p' fstab
[root@ubuntu2204 ~]# grep -Ev '^#|^$' fstab

范例:修改文件

#修改前备份
[root@ubuntu2204 ~]# seq 10 > 10.txt
[root@ubuntu2204 ~]# sed -i.bak '2,7d' 10.txt
[root@ubuntu2204 ~]# ll 10*
-rw-r--r-- 1 root root 9 Jul 23 19:02 10.txt
-rw-r--r-- 1 root root 21 Jul 23 19:01 10.txt.bak
[root@ubuntu2204 ~]# cat 10.txt
1 
8 
9
10
#不备份
[root@ubuntu2204 ~]# rm -f 10.txt.bak
[root@ubuntu2204 ~]# seq 10 > 10.txt
[root@ubuntu2204 ~]# sed -i '2,7d' 10.txt
[root@ubuntu2204 ~]# ll 10*
-rw-r--r-- 1 root root 9 Jul 23 19:05 10.txt
[root@ubuntu2204 ~]# cat 10.txt
1 
8 
9
10
#删除注释行和空行
[root@ubuntu2204 ~]# sed -i '/^#/d;/^$/d' fstab
[root@ubuntu2204 ~]# sed -i '/^\(#\|$\)/d' fstab
#搜索替换和&(引用)
[root@rocky86 0723]# sed -n 's/root/ROOT/gp' /etc/passwd
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
operator:x:11:0:operator:/ROOT:/sbin/nologin
[root@rocky86 0723]# sed -n 's/root/&er/gp' /etc/passwd
rooter:x:0:0:rooter:/rooter:/bin/bash
operator:x:11:0:operator:/rooter:/sbin/nologin
[root@rocky86 0723]# sed -n 's/r..t/&er/gp' /etc/passwd
rooter:x:0:0:rooter:/rooter:/bin/bash
operator:x:11:0:operator:/rooter:/sbin/nologin
ftp:x:14:50:FTP User:/var/fterp:/sbin/nologin
clevis:x:994:988:Clevis Decrypterion Framework unprivileged
user:/var/cache/clevis:/sbin/nologin
#除指定文件外其余删除
[root@ubuntu2204 ~]# ls
f-1.txt f-2.txt f-3.txt f-4.txt f-5.txt f-6.txt f-7.txt f-8.txt
#取非 1|3|5|7
[root@ubuntu2204 ~]# ls | grep -Ev 'f-(1|3|5|7)\.txt'
f-2.txt
f-4.txt
f-6.txt
f-8.txt
#删除非1|3|5|7
[root@ubuntu2204 ~]# rm -f `ls | grep -Ev 'f-(1|3|5|7)\.txt'`
[root@ubuntu2204 ~]# ls
f-1.txt f-3.txt f-5.txt f-7.txt
#取非 1|3|5|7
[root@ubuntu2204 ~]# ls |sed -n '/f-[^1357]\.txt/p'
f-2.txt
f-4.txt
f-6.txt
f-8.txt
#删除非1|3|5|7
[root@ubuntu2204 ~]# rm -f `ls |sed -n '/f-[^1357]\.txt/p'`
[root@ubuntu2204 ~]# ls
f-1.txt f-3.txt f-5.txt f-7.txt
[root@ubuntu2204 ~]# ls | grep -Ev 'f-(1|3|5|7)\.txt'
f-2.txt
f-4.txt
f-6.txt
f-8.txt
[root@ubuntu2204 ~]# ls | grep -Ev 'f-(1|3|5|7)\.txt' | sed -n 's/.*/rm &/p'
rm f-2.txt
rm f-4.txt
rm f-6.txt
rm f-8.txt
[root@ubuntu2204 ~]# ls | grep -Ev 'f-(1|3|5|7)\.txt' | sed -n 's/.*/rm &/p' |
bash
[root@ubuntu2204 ~]# ls
f-1.txt f-3.txt f-5.txt f-7.txt
[root@ubuntu2204 ~]# ls | grep -Ev 'f-(1|3|5|7)\.txt' | sed -En 's/(.*)/rm \1/p'
| bash
[root@ubuntu2204 ~]# ls
f-1.txt f-3.txt f-5.txt f-7.txt
#获取分区利用率
[root@ubuntu2204 ~]# df | sed -En '/^\/dev\/sd/s/.* ([0-9]+)%.*/\1/p'
14
[root@ubuntu2204 ~]# df | sed -En 's/^\/dev.* ([0-9]+)%.*/\1/p' | sort -nr
14
7

#取IP地址
[root@ubuntu2204 ~]# ifconfig ens33 |sed -nr "2s/[^0-9]+([0-9.]+).*/\1/p"
10.0.0.206
[root@ubuntu2204 ~]# ifconfig ens33 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\1/p'
10.0.0.206
[root@ubuntu2204 ~]# ifconfig ens33 | sed -rn '2s/^[^0-9]+([0-9.]+) .*$/\1/p'
10.0.0.206
[root@ubuntu2204 ~]# ifconfig ens33 | sed -n '2s/^.*inet //p' | sed -n 's/
netmask.*//p'
10.0.0.206
[root@ubuntu2204 ~]# ifconfig ens33 | sed -n '2s/^.*inet //;s/ netmask.*//p'
10.0.0.206
[root@ubuntu2204 ~]# ifconfig ens33 | sed -rn '2s/(.*inet )([0-9].*)(
netmask.*)/\2/p'
10.0.0.206
#取基名和目录名
#取基名
[root@rocky86 0723]# basename "/etc/sysconfig/network-scripts/"
network-scripts
[root@rocky86 0723]# echo "/etc/sysconfig/network-scripts/" | sed -nE 's#(^/.*/)
([^/]+)/?#\2#p'
network-scripts
#取目录
[root@rocky86 0723]# dirname "/etc/sysconfig/network-scripts/"
/etc/sysconfig
[root@rocky86 0723]# echo "/etc/sysconfig/network-scripts/" | sed -nE 's#
(^/.*)/([^/]+)/?#\1#p'
/etc/sysconfig
#取文件的前缀和后缀
[root@ubuntu2204 ~]# echo a.txt | sed -En 's/(.*)\.([^.]+)$/\1 \2/p'
a txt
[root@ubuntu2204 ~]# echo a.tar.gz.txt | sed -En 's/(.*)\.([^.]+)$/\1 \2/p'
a.tar.gz txt

#将非#开头的行加#
[root@rocky86 0723]# sed -rn ‘s/^[^#]/#&/p’ fstab
#/dev/mapper/rl-root / xfs defaults 0 0
#UUID=94a73757-555a-4d2b-8153-f54277c4c50d /boot xfs defaults 0 0
#/dev/mapper/rl-home /home xfs defaults 0 0
#/dev/mapper/rl-swap none swap defaults 0 0
[root@rocky86 0723]# sed -rn 's/^[^#](.*)/#\1/p' fstab
#/dev/mapper/rl-root / xfs defaults 0 0
#UUID=94a73757-555a-4d2b-8153-f54277c4c50d /boot xfs defaults 0 0
#/dev/mapper/rl-home /home xfs defaults 0 0
#/dev/mapper/rl-swap none swap defaults 0 0
[root@rocky86 0723]# sed -rn '/^#/!s@^@#@p' fstab
#
#/dev/mapper/rl-root / xfs defaults 0 0
#UUID=94a73757-555a-4d2b-8153-f54277c4c50d /boot xfs defaults 0 0
#/dev/mapper/rl-home /home xfs defaults 0 0
#/dev/mapper/rl-swap none swap defaults 0 0

#将#开头的行删除#
[root@rocky86 0723]# sed -ri.bak '/^#/s/^#//' fstab
[root@rocky86 0724]# sed -E -i.bak 's/^#(.*)/\1/' fstab

#取分区利用率
[root@rocky86 0723]# df | sed -nr '/^\/dev/s# .* ([0-9]+)%.*# \1#p'
/dev/mapper/rl-root 16
/dev/mapper/rl-home 1
/dev/sda1 26
[root@rocky86 0723]# df | sed -rn '/^\/dev/ s#([^[:space:]]+[[:space:]]+){4}
(.*)%.*#\2#p'
16
1
26
[root@rocky86 0723]# df | sed -rn '/^\/dev/ s#(\S+\s+){4}(.*)%.*#\2#p'
16
1
26

#修改网卡名称
#centos7,8
[root@rocky86 0723]# sed -Ei.bak 's/^(GRUB_CMDLINE_LINUX=.*)"$/\1
net.ifnames=0"/' /etc/default/grub
[root@rocky86 0723]# sed -Ei '/^GRUB_CMDLINE_LINUX/s#"$# net.ifnames=0"#'
/etc/default/grub
#修改完成后重启生效
[root@rocky86 0723]# grub2-mkconfig -o /etc/grub2.cfg;reboot;
#ubuntu2204
[root@ubuntu2204 ~]# sed -Ei '/^GRUB_CMDLINE_LINUX/s#"$# net.ifnames=0"#'
/etc/default/grub
[root@ubuntu2204 ~]# grub-mkconfig -o /boot/grub/grub.cfg;reboot

#修改selinux配置
[root@rocky86 0723]# cp /etc/selinux/config ./
[root@rocky86 0723]# sed -i.bak '/SELINUX=enforcing/c SELINUX=disabled' config
[root@rocky86 0723]# sed -i.bak '/^SELINUX=/c SELINUX=disabled/' config
[root@rocky86 0723]# sed -Ei.bak 's/^SELINUX=.*/SELINUX=disabled/' config
[root@rocky86 0723]# sed -Ei.bak 's/^(SELINUX=)(.*)/\1disabled/' config

#显示前4行
[root@ubuntu2204 ~]# seq 10 > test.txt
[root@ubuntu2204 ~]# sed 4q test.txt
1 
2 
3 
4

高级用法 

sed 中除了模式空间,还另外还支持保持空间(Hold Space),利用此空间,可以将模式空间中的数据,临时保存至保持空间,从而后续接着处理,实现更为强大的功能。

常见的高级命令:

P #打印模式空间开端至\n内容,并追加到默认输出之前
h #把模式空间中的内容覆盖至保持空间中
H #把模式空间中的内容追加至保持空间中
g #从保持空间取出数据覆盖至模式空间
G #从保持空间取出内容追加至模式空间
x #把模式空间中的内容与保持空间中的内容进行互换
n #读取匹配到的行的下一行覆盖至模式空间
N #读取匹配到的行的下一行追加至模式空间
d #删除模式空间中的行
D #如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入
行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循
环

范例:

sed -n 'n;p' FILE
seq 10 | sed 'N;s/\n//'
sed '1!G;h;$!d' FILE
seq 10 | sed -n '/3/{g;1!p;};h' #前一行
seq 10 | sed -nr '/3/{n;p}' #后一行
sed 'N;D'FILE
seq 10 |sed '3h;9G;9!d'
sed '$!N;$!D' FILE
sed '$!d' FILE
sed 'G' FILE
sed 'g' FILE
sed '/^$/d;G' FILE
sed 'n;d' FILE
sed -n '1!G;h;$p' FILE


#打印偶数行
[root@ubuntu2204 ~]# seq 10 | sed -n 'n;p'
2 
4 
6 
8
10
[root@ubuntu2204 ~]# seq 10 | sed -n '2~2p'
2 
4 
6 
8
10
[root@ubuntu2204 ~]# seq 10 | sed '1~2d'
2 
4 
6 
8
10
[root@ubuntu2204 ~]# seq 10 | sed -n '1~2!p'
2 
4 
6 
8
10

格式化输出 printf

相当于增强版的 echo,实现丰富的格式化输出

格式:

printf format args...

常用格式替换符

替换符功能
%s字符串
%d,%i十进制整数
%f浮点格式
%cASCII字符,即显示对应参数的第一个字符
%b相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转 义
%o八进制值
%u不带正负号的十进制值
%x十六进制值(a-f)
%X十六进制值(A-F)
%%表示%本身

说明:

%[N]s # N表示输出宽度,不够补空格 -N 表示左对齐
%[0][N]d # 0表示宽度不够时在左边补0,N表示输出宽度
%[.N]f # .N 表示保留的小数位

常用转义字符

转义符功能
\a警告字符,通常为ASCII的BEL字符
\b后退
\f换页
\n换行
\r回车
\t水平制表符
\v垂直制表符
\表示\本身

范例:

[root@ubuntu2204 ~]# printf "%s" 1 2 3 4
1234[root@ubuntu2204 ~]#
[root@ubuntu2204 ~]# printf "%s\n" 1 2 3 4
1 2 3 4
[root@ubuntu2204 ~]# printf "%f\n" 1 2 3 4
1.000000
2.000000
3.000000
4.000000
#.2f 表示保留两位小数
[root@ubuntu2204 ~]# printf "%.2f\n" 1 2 3 4
1.00
2.00
3.00
4.00
[root@ubuntu2204 ~]# printf "(%s)" 1 2 3 4;echo
(1)(2)(3)(4)
[root@ubuntu2204 ~]# printf " (%s) " 1 2 3 4;echo
 (1)  (2)  (3)  (4)
[root@ubuntu2204 ~]# printf "(%s)\n" 1 2 3 4
(1)
(2)
(3)
(4)
[root@ubuntu2204 ~]# printf "%s %s\n" 1 2 3 4
1 2
3 4
[root@ubuntu2204 ~]# printf "%s %s %s\n" 1 2 3 4
1 2 3
4
#%-10s 表示宽度10个字符,左对齐
[root@ubuntu2204 ~]# printf "%-10s %-10s %-4s %s \n" 姓名 性别 年龄 体重 小明 男 20 70 小红 女 18 50
姓名 性别 年龄 体重
小明 男 20 70
小红 女 18 50
#将十进制的17转换成16进制数
[root@ubuntu2204 ~]# printf "%X" 17
11[root@ubuntu2204 ~]#
#将十六进制转换成十进制
[root@ubuntu2204 ~]# printf "%d\n" 0xC
12
[root@ubuntu2204 ~]# VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m " $VAR
welcome to Magedu
[root@ubuntu2204 ~]# VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m\n" $VAR
welcome
to
Magedu
[root@ubuntu2204 ~]# VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m\n" "$VAR"
welcome to Magedu

二、Grep命令的基本正则和扩展正则 

REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式;其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能;但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符;

正则表达式分两类:

  • 基本正则表达式:BRE Basic Regular Expressions;
  • 扩展正则表达式:ERE Extended Regular Expressions;

帮助:man 7 regex

基本正则表达式元字符 

字符匹配 

. #匹配任意单个字符(除了\n),可以是一个汉字或其它国家的文字
[] #匹配指定范围内的任意单个字符,示例:[wang] [0-9] [a-z] [a-zA-Z]
[^] #匹配指定范围外的任意单个字符,示例:[^wang]
[:alnum:] #字母和数字
[:alpha:] #代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] #小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] #大写字母
[:blank:] #空白字符(空格和制表符)
[:space:] #包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包
含的范围广
[:cntrl:] #不可打印的控制字符(退格、删除、警铃...)
[:digit:] #十进制数字
[:xdigit:] #十六进制数字
[:graph:] #可打印的非空白字符
[:print:] #可打印字符
[:punct:] #标点符号
---------------------------------------
\s #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [\f\r\t\v],
Unicode正则表达式会匹配全角空格符
\S #匹配任何非空白字符。等价于 [^\f\r\t\v]
\w #匹配一个字母,数字,下划线,汉字,其它国家文字的字符,等价于[_[:alnum:]字]
\W #匹配一个非字母,数字,下划线,汉字,其它国家文字的字符,等价于[^_[:alnum:]字]

范例:匹配任意单个字符

[root@ubuntu2204 ~]# grep "r.t" /etc/passwd
[root@ubuntu2204 ~]# grep "r..t" /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@rocky8 ~]# grep "r.t" /etc/passwd
operator:x:11:0:operator:/root:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
[root@ubuntu2204 ~]# echo a你好b | grep a..b
a你好b
[root@ubuntu2204 ~]# echo aaa你好b | grep a..b
aaa你好b
[root@ubuntu2204 ~]# echo a你-b | grep a..b
a你-b

范例:范围匹配

[root@centos8 ~]#ls /etc/ | grep 'rc[.0-6]'
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local
[root@centos8 ~]#ls /etc/ | grep 'rc[.0-6].'
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local
[root@centos8 ~]#ls /etc/ | grep 'rc[.0-6]\.'
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
[root@ubuntu2204 ~]# echo ma | grep '[lnm]'
ma
[root@ubuntu2204 ~]# echo ma | grep '[^lnm]'
ma
[root@ubuntu2204 ~]# echo "ab1c2d3e4444fABCg$%^" | grep "[0-Z]"
ab1c2d3e4444fABCg$%^
[root@ubuntu2204 ~]# echo "ab1c2d3e4444fABCg$%^" | grep "[0-9]"
ab1c2d3e4444fABCg$%^
[root@ubuntu2204 ~]# echo "ab1c2d3e4444fABCg$%^" | grep "[a-z]"
ab1c2d3e4444fABCg$%^
[root@ubuntu2204 ~]# echo "ab1c2d3e4444fABCg$%^" | grep "[A-Z]"
ab1c2d3e4444fABCg$%^
[root@ubuntu2204 ~]# echo "ab1c2d3e4444fABCg$%^" | grep "[^0-Z]"
ab1c2d3e4444fABCg$%^
[root@ubuntu2204 ~]# echo "ab1c2d3e4444fABCg$%^" | grep "[[:punct:]]"
ab1c2d3e4444fABCg$%^

#匹配空格
[root@ubuntu2204 ~]# echo "1 2 3" | grep "[[:blank:]]"
1 2 3
#匹配非空格
[root@ubuntu2204 ~]# echo "1 2 3" | grep "[^[:blank:]]"
1 2 3

匹配次数 

用在要指定次数的字符后面,用于指定前面的字符要出现的次数

* #匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* #任意长度的任意字符
\? #匹配其前面的字符出现0次或1次,即:可有可无
\+ #匹配其前面的字符出现最少1次,即:肯定有且 >=1 次
\{n\} #匹配前面的字符n次
\{m,n\} #匹配前面的字符至少m次,至多n次
\{,n\} #匹配前面的字符至多n次,<=n
\{n,\} #匹配前面的字符至少n次

范例:

[root@ubuntu2204 ~]# echo "rt" | grep "ro*t"
rt
[root@ubuntu2204 ~]# echo "rot" | grep "ro*t"
rot
[root@ubuntu2204 ~]# echo "root" | grep "ro*t"
root
[root@ubuntu2204 ~]# echo "roooooooot" | grep "ro*t"
roooooooot

#任意长度任意字符
[root@ubuntu2204 ~]# grep "r.*t" /etc/passwd

#0次或1次
[root@ubuntu2204 ~]# echo /etc/ |grep "/etc/\?"
/etc/
[root@ubuntu2204 ~]# echo /etc |grep "/etc/\?"
/etc

#1次或多次
[root@ubuntu2204 ~]# echo google | grep "go\+gle"
google
[root@ubuntu2204 ~]# echo gogle | grep "go\+gle"
gogle
[root@ubuntu2204 ~]# echo ggle | grep "go\+gle"
[root@ubuntu2204 ~]# echo gooogle | grep "go\+gle"
gooogle

#自定义次数
#2次
[root@ubuntu2204 ~]# echo google | grep "go\{2\}gle"
google
#2次到5次
[root@ubuntu2204 ~]# echo google | grep "go\{2,5\}gle"
google
#2次到多次
[root@ubuntu2204 ~]# echo google | grep "go\{2,\}gle"
google
#0次到2次
[root@ubuntu2204 ~]# echo google | grep "go\{,2\}gle"
google

#匹配正负数
[root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep '-\?[0-9]\+'
grep: invalid option -- '\'
Usage: grep [OPTION]... PATTERNS [FILE]...
Try 'grep --help' for more information.
[root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep '\-\?[0-9]\+'
-1 -2 123 -123 234
[root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E '-?[0-9]+'
grep: invalid option -- '?'
Usage: grep [OPTION]... PATTERNS [FILE]...
Try 'grep --help' for more information.
[root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E '\-?[0-9]+'
-1 -2 123 -123 234
[root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E -- '-?[0-9]+'
-1 -2 123 -123 234
[root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E '(-)?[0-9]+'
-1 -2 123 -123 234

#取IP地址
[root@ubuntu2204 ~]# ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.206 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20c:29ff:fe11:98d9 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:11:98:d9 txqueuelen 1000 (Ethernet)
RX packets 13925 bytes 1496342 (1.4 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 13185 bytes 3218569 (3.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@ubuntu2204 ~]# ifconfig ens33|grep netmask |grep -o '[0-9]\{1,3\}\.[0-9]\
{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'|head -n1
10.0.0.206
[root@ubuntu2204 ~]# ifconfig ens33|grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\
{1,3\}\.[0-9]\{1,3\}'|head -n1
10.0.0.206

位置锚定 

位置锚定可以用于定位出现的位置

^ #行首锚定, 用于模式的最左侧
$ #行尾锚定,用于模式的最右侧
^PATTERN$ #用于模式匹配整行
^$ #空行
^[[:space:]]*$ #空白行
\< 或 \b #词首锚定,用于单词模式的左侧
\> 或 \b #词尾锚定,用于单词模式的右侧
\<PATTERN\> #匹配整个单词
#注意: 单词是由字母,数字,下划线组成

范例:

#以 # 开头
[root@ubuntu2204 ~]# grep "^#" /etc/fstab
#以 bash 结尾
[root@ubuntu2204 ~]# grep "bash$" /etc/passwd
#所有空行
[root@ubuntu2204 ~]# grep "^$" /etc/profile
#所有非空行
[root@ubuntu2204 ~]# grep -v "^$" /etc/profile
#所有非注释行
[root@ubuntu2204 ~]# grep "^[^#]" /etc/profile
#排除所有空行和注释行
[root@ubuntu2204 ~]# grep -v "^$" /etc/profile | grep -v "^#" /etc/profile
#同上
[root@ubuntu2204 ~]# grep -v -e "^$" /etc/profile -v -e "^#" /etc/profile
#同上
[root@ubuntu2204 ~]# grep -v '^$\|^#' /etc/profile
#匹配单词
[root@ubuntu2204 ~]# echo mage | grep "\<mage\>"
[root@ubuntu2204 ~]# echo mage- | grep "\<mage\>"
[root@ubuntu2204 ~]# echo magee | grep "\<mage\>"

范例:

[root@centos8 ~]#grep '^[^#]' /etc/fstab
UUID=acf9bd1f-caae-4e28-87be-e53afec61347 / xfs defaults
0 0
UUID=1770b87e-db5a-445e-bff1-1653ac64b3d6 /boot ext4 defaults
1 2
UUID=ffffd919-d674-44d9-a4e7-402874f0a1f0 /data xfs defaults
0 0
UUID=409e36d2-ac5e-423f-ad78-9b12db4576bd swap swap defaults
0 0
[root@ubuntu2204 ~]# grep '^[^#]' /etc/fstab
/dev/disk/by-id/dm-uuid-LVM-
2DfhG2JAeOckxicJorCIykZWj5F57OAw1wUxIh2DKVkhusX3fhgEVlJJIPV3tnGn / ext4 defaults
0 1
/dev/disk/by-uuid/195992f6-95be-4629-b331-8fb09cf99819 /boot ext4 defaults 0 1
/swap.img none swap sw 0 0

分组其它 

分组 

分组:() 将多个字符捆绑在一起,当作一个整体处理,如:(root)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, ...
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
注意: \0 表示正则表达式匹配的所有字符

范例:

#ab,然后c出现3次
[root@ubuntu2204 ~]# echo abccc | grep "abc\{3\}"
abccc
#abc作为一个整体出现3次
[root@ubuntu2204 ~]# echo abcabcabc | grep "\(abc\)\{3\}"
abcabcabc
#后向引用
[root@ubuntu2204 ~]# echo abcabcabc | grep "\(abc\)\1"
abcabcabc
[root@ubuntu2204 ~]# echo abcabcabc | grep "\(abc\)\1\1"
abcabcabc
#\1表示引用第一个分组的内容,即 abc
[root@ubuntu2204 ~]# echo "abcdefabc" | grep "\(abc\)def\1"
abcdefabc
#\1表示引用第一个分组的内容,即abc,\{3\}表示引用内容出现3次
[root@ubuntu2204 ~]# echo abc-def-abcabcabc | grep "^\(abc\)-\(def\)-\1\{3\}"
abc-def-abcabcabc
[root@ubuntu2204 ~]# echo abc-def-abcabcabc-def-abc-defdef | grep "^\(abc\)-\
(def\)-\1\{3\}-\2-\1-\2\{2\}"
abc-def-abcabcabc-def-abc-defdef
#取IP
[root@ubuntu2204 ~]# ifconfig ens33 | grep -o "\([0-9]\{1,3\}\.\)\{3\}[0-9]\
{1,3\}" | head -n 1
10.0.0.158

注意: 后向引用引用前面的分组括号中的模式所匹配字符,而非模式本身 

或者 

范例:

a\|b #a或b
C\|cat #C或cat
\(C\|c\)at #Cat或cat
#a或b a\|b
[root@ubuntu2204 ~]# echo "a" | grep "a\|b"
a
[root@ubuntu2204 ~]# echo "b" | grep "a\|b"
b
[root@ubuntu2204 ~]# echo "ab" | grep "a\|b"
ab
[root@ubuntu2204 ~]# echo "abc" | grep "a\|b"
abc
[root@ubuntu2204 ~]# echo "cab" | grep "a\|b"
cab
[root@ubuntu2204 ~]# echo "acb" | grep "a\|b"
acb
#12a 或 b 12a\|b
[root@ubuntu2204 ~]# echo "12a" | grep "12a\|b"
12a
[root@ubuntu2204 ~]# echo "b" | grep "12a\|b"
b
[root@ubuntu2204 ~]# echo "12ab" | grep "12a\|b"
12ab
[root@ubuntu2204 ~]# echo "12ba" | grep "12a\|b"
12ba
#12a 或 12b 12a\|12b
[root@ubuntu2204 ~]# echo "12a" | grep "12a\|12b"
12a
[root@ubuntu2204 ~]# echo "12b" | grep "12a\|12b"
12b
[root@ubuntu2204 ~]# echo "12ab" | grep "12a\|12b"
12ab
[root@ubuntu2204 ~]# echo "12ba" | grep "12a\|12b"
12ba
#12a 或 12b 12\(a\|b\)
[root@ubuntu2204 ~]# echo "12a" | grep "12\(a\|b\)"
12a
[root@ubuntu2204 ~]# echo "12b" | grep "12\(a\|b\)"
12b
[root@ubuntu2204 ~]# echo "12ab" | grep "12\(a\|b\)"
12ab
[root@ubuntu2204 ~]# echo "12ba" | grep "12\(a\|b\)"
12ba
#12a 或 12b 12[ab]
[root@ubuntu2204 ~]# echo "12a" | grep "12[ab]"
12a
[root@ubuntu2204 ~]# echo "12b" | grep "12[ab]"
12b
[root@ubuntu2204 ~]# echo "12ab" | grep "12[ab]"
12ab
[root@ubuntu2204 ~]# echo "12ba" | grep "12[ab]"
12ba

范例:排除空行和#开头的行

[root@ubuntu2204 ~]# grep -v '^#' /etc/apache2/apache2.conf |grep -v ^$
[root@ubuntu2204 ~]# grep -v '^#\|^$' /etc/apache2/apache2.conf
[root@ubuntu2204 ~]# grep -v '^\(#\|$\)' /etc/apache2/apache2.conf
[root@ubuntu2204 ~]# grep "^[^#]" /etc/apache2/apache2.conf

扩展正则表达式元字符 

字符匹配 

. #任意单个字符
[wang] #指定范围的字符
[^wang] #不在指定范围的字符
[:alnum:] #字母和数字
[:alpha:] #代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] #小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] #大写字母
[:blank:] #空白字符(空格和制表符)
[:space:] #水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] #不可打印的控制字符(退格、删除、警铃...)
[:digit:] #十进制数字
[:xdigit:] #十六进制数字
[:graph:] #可打印的非空白字符
[:print:] #可打印字符
[:punct:] #标点符号

匹配次数 

* #匹配前面字符任意次
? #0或1次
+ #1次或多次
{n} #匹配n次
{m,n} #至少m,至多n次

 位置锚定

^ #行首
$ #行尾
\<, \b #词首
\>, \b #词尾

分组其它 

() 分组 #后向引用:\1, \2, ... 注意: \0 表示正则表达式匹配的所有字符
| #或者
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat

范例:

[root@rocky86 ~]# ifconfig | grep -Ewo "(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"|head -n1
10.0.0.155

三、变量命名规则 

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据
数据要存在内存空间中,而内存空间又是通过内存地址来访问的,但内存地址一般是16进制的编号;
为了方便使用,就有了变量名,当访问一个变量时,实际是访问其对应的内存地址的那块内存空间;

变量类型 

变量类型:

  • 内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
  • 用户自定义变量

不同的变量存放的数据不同,决定了以下

  • 数据存储方式
  • 参与的运算
  • 表示的数据范围

变量数据类型:

  • 字符
  • 数值:整型、浮点型,bash 不支持浮点数
  • 布尔
  • 指针
  • 结构体:自定义的复合类型的数据类型
  • ........

shell中变量命名法则 

命名要求 

  • 区分大小写
  • 不能使程序中的保留字和内置变量:如:if,for
  • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反

 命名习惯

  • 见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
  • 变量名大写
  • 局部变量小写
  • 函数名小写
  • 大驼峰StudentFirstName,由多个单词组成,且每个单词的首字母是大写,其它小写
  • 小驼峰studentFirstName ,由多个单词组成,第一个单词的首字母小写,后续每个单词的首字母是大写,其它小写
  • 下划线: student_first_name

变量定义和引用 

变量的生效范围等标准划分变量类型

  • 普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell 进程均无效
  • 环境变量:生效范围为当前shell进程及其子进程
  • 本地变量:生效范围为当前shell进程中某代码片断,通常指函数

变量赋值:

name='value'

value 可以是以下多种形式

name='root' #直接字串
name="$USER" #变量引用
name=`COMMAND` #命令引用
name=$(COMMAND) #命令引用

注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除 

变量引用:

$name
${name}

弱引用和强引用

  • "$name" 弱引用,其中的变量引用会被替换为变量值
  • '$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串

范例:变量的各种赋值方式和引用

[root@ubuntu2204 ~]# TITLE='cto'
[root@ubuntu2204 ~]# echo $TITLE
cto
[root@ubuntu2204 ~]# echo I am $TITLE
I am cto
[root@ubuntu2204 ~]# echo "I am $TITLE"
I am cto
[root@ubuntu2204 ~]# echo 'I am $TITLE'
I am $TITLE
[root@ubuntu2204 ~]# NAME=$USER
[root@ubuntu2204 ~]# echo $NAME
root
[root@ubuntu2204 ~]# USER=`whoami`
[root@ubuntu2204 ~]# echo $USER
root
#命令执行结果赋值
[root@ubuntu2204 ~]# FILE=`ls /run`
[root@ubuntu2204 ~]# echo $FILE
agetty.reload atd.pid auditd.pid autofs.fifo-misc autofs.fifo-net console cron.reboot cryptsetup dbus faillock
fsck initctl initramfs lock log mount NetworkManager plymouth rsyslogd.pid screen sepermit setrans sshd.pid
sssd.pid sudo systemd tmpfiles.d tuned udev user utmp vmware
[root@ubuntu2204 ~]# FILE=/etc/*
[root@ubuntu2204 ~]# echo $FILE
/etc/adjtime /etc/aliases /etc/alternatives /etc/anacrontab /etc/at.deny /etc/audit /etc/authselect
/etc/autofs.conf /etc/autofs_ldap_auth.conf

保留格式

[root@ubuntu2204 ~]# seq 5
1 2 3 4 5
[root@ubuntu2204 ~]# NUM=`seq 5`
[root@ubuntu2204 ~]# echo $NUM
1 2 3 4 5
[root@ubuntu2204 ~]# echo "$NUM"
1 2 3 4 5
[root@ubuntu2204 ~]# NAMES="wang
> zhang
> zhao
> li"
[root@ubuntu2204 ~]# echo $NAMES
wang zhang zhao li
[root@ubuntu2204 ~]# echo "$NAMES"
wang
zhang
zhao
li

范例:变量引用

[root@ubuntu2204 ~]# NAME=mage
[root@ubuntu2204 ~]# AGE=20
[root@ubuntu2204 ~]# echo $NAME
mage
[root@ubuntu2204 ~]# echo $AGE
20
[root@ubuntu2204 ~]# echo $NAME $AGE
mage 20
[root@ubuntu2204 ~]# echo $NAME$AGE
mage20
[root@ubuntu2204 ~]# echo $NAME_$AGE
20
[root@ubuntu2204 ~]# echo ${NAME}_$AGE
mage_20

范例:变量的间接赋值和引用

[root@ubuntu2204 ~]# TITLE=cto
[root@ubuntu2204 ~]# NAME=wang
[root@ubuntu2204 ~]# TITLE=$NAME
[root@ubuntu2204 ~]# echo $NAME
wang
[root@ubuntu2204 ~]# echo $TITLE
wang
[root@ubuntu2204 ~]# NAME=mage
[root@ubuntu2204 ~]# echo $NAME
mage
[root@ubuntu2204 ~]# echo $TITLE
wang

范例:变量追加值

[root@ubuntu2204 ~]# TITLE=CTO
[root@ubuntu2204 ~]# TITLE+=:wang
[root@ubuntu2204 ~]# echo $TITLE
CTO:wang

范例:利用变量实现动态命令

[root@ubuntu2204 ~]# CMD=hostname
[root@ubuntu2204 ~]# $CMD
centos8.magedu.com

范例:将 sysinfo.sh 中的颜色定义成变量

[root@ubuntu2204 ~]# vim sysinfo.sh
#!/bin/bash
#
#****************************************************
#Author: jose
#QQ: 123456
#Date: 2023-12-08
#FileName: sysinfo.sh
#URL: http://www.magedu.com
#Description: test
#Copyright(C): 2023 All right
#***************************************************
COLOR=34
echo -e "========================= sysinfo begin ================\n"
echo -e "CPU \c"
echo -e "\E[1;${COLOR}m `lscpu | sed -nr 's/^Model name: +(.*)/\1/p'` \E[0m"
echo -e "Mem \c"
echo -e "\E[1;${COLOR}m `cat /proc/meminfo | head -n 1 | tr -s " " | cut -d" " -f2,3` \E[0m"
echo -e "DISK \c"
echo -e "\E[1;${COLOR}m `lsblk /dev/sda | grep "^sda" | tr -s " " | cut -d" " -f4` \E[0m"
echo -e "OS \c"
echo -e "\E[1;${COLOR}m `cat /etc/os-release | sed -nr 's/^VERSION=\"(.*)\"/\1/p'` \E[0m"
echo -e "\n========================= sysinfo end =================="

显示已定义的所有变量:

set

删除变量:

unset <name>

范例:

[root@ubuntu2204 ~]# NAME=mage
[root@ubuntu2204 ~]# TITLE=ceo
[root@ubuntu2204 ~]# echo $NAME $TITLE
mage ceo
[root@ubuntu2204 ~]# unset NAME TITLE
[root@ubuntu2204 ~]# echo $NAME $TITLE

范例:显示系统信息

[root@ubuntu2204 ~]# vim sysinfo-v5.sh
#!/bin/bash
#
#****************************************************
#Author: jose
#QQ: 123456
#Date: 2023-12-08
#FileName: sysinfo-v5.sh
#URL: http://www.magedu.com
#Description: test
#Copyright(C): 2023 All right
#***************************************************
RED="\E[1;31m"
GREEN="echo -e \E[1;32m"
END="\E[0m"
. /etc/os-release
$GREEN----------------------- sysinfo begin --------------------$END
echo -e "HOSTNAME: $RED`hostname`$END"
echo -e "IPADDR: $RED` ifconfig eth0|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' |head -n1`$END"
echo -e "IPADDR: $RED` hostname -I`$END"
echo -e "OSVERSION: $RED$PRETTY_NAME$END"
echo -e "KERNEL: $RED`uname -r`$END"
echo -e "CPU: $RED`lscpu|grep '^Model name'|tr -s ' '|cut -d : -f2`$END"
echo -e "MEMORY: $RED`free -h|grep Mem|tr -s ' ' : |cut -d : -f2`$END"
echo -e "DISK: $RED`lsblk |grep '^sd' |tr -s ' ' |cut -d " " -f4`$END"
$GREEN----------------------- sysinfo end ----------------------------------$END

环境变量 

环境变量:

  • 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
  • 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
  • 一般只在系统配置文件中使用,在脚本中较少使用

变量声明和赋值:

#声明并赋值
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name

变量引用:

$name
${name}

显示所有环境变量:

env
printenv
export
declare -x

查看指定进程的环境变量:

cat /proc/$PID/environ

删除变量:

unset name

bash内置的环境变量:

PATH
SHELL
USER
UID
HOME
PWD
SHLVL #shell的嵌套层数,即深度
LANG
MAIL
HOSTNAME
HISTSIZE
_ #下划线,表示前一命令的最后一个参数

 范例:查看进程的环境变量

[root@ubuntu2204 ~]# cat /proc/1235/environ
USER=rootLOGNAME=rootHOME=/rootPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/binSHELL=/bin/bashTERM=linux
SSH_AUTH_SOCK=/tmp/ssh•iIeuAxdLiY/agent.1234XDG_SESSION_ID=1XDG_RUNTIME_DIR=/run/user/0DBUS_SESSION_BUS_ADDRES
S=unix:path=/run/user/0/busSSH_CLIENT=10.0.0.1 1325822SSH_CONNECTION=10.0.0.1 13258
10.0.0.822SSH_TTY=/dev/pts/0[root@centos8 ~]#
[root@ubuntu2204 ~]# cat /proc/1235/environ |tr '\0' '\n'
USER=root
LOGNAME=root
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
SHELL=/bin/bash
TERM=linux
SSH_AUTH_SOCK=/tmp/ssh-iIeuAxdLiY/agent.1234
XDG_SESSION_ID=1
XDG_RUNTIME_DIR=/run/user/0
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus
SSH_CLIENT=10.0.0.1 13258 22
SSH_CONNECTION=10.0.0.1 13258 10.0.0.8 22
SSH_TTY=/dev/pts/0

只读变量 

只读变量:只能声明定义,但后续不能修改和删除,即常量
声明只读变量:

readonly name
declare -r name

查看只读变量:

readonly [-p]
declare -r

范例:

[root@ubuntu2204 ~]# readonly PI=3.14159
[root@ubuntu2204 ~]# echo $PI
3.14159
[root@ubuntu2204 ~]# PI=3.14
-bash: PI: readonly variable
[root@ubuntu2204 ~]# unset PI
-bash: unset: PI: cannot unset: readonly variable
[root@ubuntu2204 ~]# echo $PI
3.14159
[root@ubuntu2204 ~]# exit
logout
Connection closed by foreign host.
Disconnected from remote host(10.0.0.8) at 14:27:04.
Type `help' to learn how to use Xshell prompt.
[c:\~]$
Reconnecting in 1 seconds. Press any key to exit local shell.
.
Connecting to 10.0.0.8:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
WARNING! The remote SSH server rejected X11 forwarding request.
Last login: Wed Apr 1 13:51:28 2020 from 10.0.0.1
[root@ubuntu2204 ~]# echo $PI

位置变量 

位置变量:在bash shell中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数

$1,$2,... #对应第1个、第2个等参数,shift [n]换位置
$0 #命令本身,包括路径
$* #传递给脚本的所有参数,全部参数合为一个字符串
$@ #传递给脚本的所有参数,每个参数为独立字符串
$# #传递给脚本的参数的个数
#注意:$@ $* 只在被双引号包起来的时候才会有差异

清空所有位置变量

set --

范例:

[root@ubuntu2204 ~]# cat /data/scripts/arg.sh
#!/bin/bash
#
#****************************************************
#Author: jose
#QQ: 123456
#Date: 2022-08-17
#FileName: arg.sh
#URL: http://www.magedu.com
#Description: test
#Copyright(C): 2022 All right
#***************************************************
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "10st arg is ${10}"
echo "11st arg is ${11}"
echo "The number of arg is $#"
echo "All args are $*"
echo "All args are $@"
echo "The scriptname is `basename $0`"
[root@ubuntu2204 ~]# bash /data/scripts/arg.sh {a..z}
1st arg is a
2st arg is b
3st arg is c
10st arg is j
11st arg is k
The number of arg is 26
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
The scriptname is arg.sh

范例:$*和$@的区别

[root@ubuntu2204 ~]# cat f1.sh
#!/bin/bash
echo "f1.sh:all args are $@"
echo "f1.sh:all args are $*"
./file.sh "$*"
[root@ubuntu2204 ~]# cat f2.sh
#!/bin/bash
echo "f2.sh:all args are $@"
echo "f2.sh:all args are $*"
./file.sh "$@"
[root@ubuntu2204 ~]# cat file.sh
#!/bin/bash
echo "file.sh:1st arg is $1"
[root@ubuntu2204 ~]# ./f1.sh a b c
f1.sh:all args are a b c
f1.sh:all args are a b c
file.sh:1st arg is a b c
[root@ubuntu2204 ~]# ./f2.sh a b c
f2.sh:all args are a b c
f2.sh:all args are a b c
file.sh:1st arg is a

范例:利用软链接实现同一个脚本不同功能

[root@ubuntu2204 ~]# cat test.sh
#!/bin/bash
#********************************************************************
echo $0
[root@ubuntu2204 ~]# ln -s test.sh a.sh
[root@ubuntu2204 ~]# ln -s test.sh b.sh
[root@ubuntu2204 ~]# ./a.sh
./a.sh
[root@ubuntu2204 ~]# ./b.sh
./b.sh

退出状态码变量 

进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255

$? #0代表成功,1-255代表失败

范例:

[root@ubuntu2204 ~]# curl -fs http://www.baidu.com >/dev/null
[root@ubuntu2204 ~]# echo $?
0

用户可以在脚本中使用以下命令自定义退出状态码

exit [n]

注意:

  • 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
  • 如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
  • 如果没有exit命令,即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一 条命令的状态码

 展开命令行

展开命令执行顺序

把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配符*、?、[abc]等等
准备I/0重导向 <、>
运行命令

防止扩展

\ #反斜线 会使随后的字符按原意解释

范例:

[root@ubuntu2204 ~]# echo Your cost: \$5.00
Your cost: $5.00
[root@ubuntu2204 ~]# echo "The book's price is \$10"
The book's price is $10

加引号来防止扩展

'' #单引号 防止所有扩展
"" #双引号 也可防止扩展,但是以下情况例外 $

变量扩展

`` #反引号,命令替换
\ #反斜线,禁止单个字符扩展
! #叹号,历史命令替换

范例:``和$() 区别

[root@ubuntu2204 ~]# echo `echo \`
> ^C
[root@ubuntu2204 ~]# echo `echo \\`
\
[root@ubuntu2204 ~]# echo `echo \\\`
> ^C
[root@ubuntu2204 ~]# echo `echo \\\\`
\
[root@ubuntu2204 ~]# echo $(echo \)
> ^C
[root@ubuntu2204 ~]# echo $(echo \\)
\
[root@ubuntu2204 ~]# echo $(echo \\\)
> ^C
[root@ubuntu2204 ~]# echo $(echo \\\\)
\\

脚本安全和set 

set 命令:可以用来定制 shell 环境
$- 变量

选项含义备注
hhashall开启hash表缓存外部命令路径
iinteractive-comments表示当前是交互是shell
mmonitor开启监控模式,可通过 Job control来控制进程的停止、继续,后台或者前台执行等
Bbraceexpand是否支持大括号扩展
Hhistory是否可用 ! 快速展开history命令

范例:

#查看命令行下的配置
[root@ubuntu2204 ~]# echo $-
himBHs
#查看脚本中的配置
[root@ubuntu2204 ~]# cat set.sh
#!/bin/bash
#
#****************************************************
#Author: jose
#QQ: 123456
#Date: 2023-12-08
#FileName: set.sh
#URL: http://www.magedu.com
#Description: test
#Copyright(C): 2023 All right
#***************************************************
echo $-
[root@ubuntu2204 ~]# bash set.sh
hb

范例:关闭hash缓存功能

[root@ubuntu2204 ~]# echo $-
himBHs
[root@ubuntu2204 ~]# hash
hits command
6 /usr/bin/bash
2 /usr/bin/cat
6 /usr/bin/vim
[root@ubuntu2204 ~]# set +h
[root@ubuntu2204 ~]# echo $-
imBHs
[root@ubuntu2204 ~]# hash
-bash: hash: hashing disabled

范例:关闭大括号展开

[root@ubuntu2204 ~]# echo $-
imBHs
[root@ubuntu2204 ~]# echo {1..5}
1 2 3 4 5
[root@ubuntu2204 ~]# set +B
[root@ubuntu2204 ~]# echo $-
imHs
[root@ubuntu2204 ~]# echo {1..5}
{1..5}

set 命令实现脚本安全

字符作用
u开启此项,在使用一个没有声明的变量时,会报错,并且终止程序,同 set -o nounset
e开启此项,命令返回非0就退出,不再继续执行后面的代码,同 set -o errexit
oset -o 显示所有; set -o option 开启 option 项; set +o option 关闭 option 项
xset -x
  • -u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset
  • -e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit
  • -o option 显示,打开或者关闭选项 显示选项:set -o 打开选项:set -o 选项 关闭选项:set +o 选项
  • -x 当执行命令时,打印命令及其参数,类似 bash -x

范例:

[root@ubuntu2204 ~]# set -o
allexport off
braceexpand on
emacs on
errexit off
errtrace off
functrace off
hashall on
histexpand on
history on
ignoreeof off
interactive-comments on
keyword off
monitor on
noclobber off
noexec off
noglob off
nolog off
notify off
nounset off
onecmd off
physical off
pipefail off
posix off
privileged off
verbose off
vi off
xtrace off

范例:限制使用没声明的变量

[root@ubuntu2204 ~]# cat set2.sh
#!/bin/bash
#
#****************************************************
#Author: jose
#QQ: 123456
#Date: 2023-12-08
#FileName: set2.sh
#URL: http://www.magedu.com
#Description: test
#Copyright(C): 2023 All right
#***************************************************
set -u
DIR=/test
rm -rf ${DIr}/* #这个变量其实不存在,如果没有 set -u 选项,则会删除根目录
rm -rf /*
[root@ubuntu2204 ~]# bash set2.sh
set2.sh: line 17: DIr: unbound variable

范例:遇到错误终止

[root@ubuntu2204 ~]# vim set3.sh
#!/bin/bash
#
#****************************************************
#Author: jose
#QQ: 123456
#Date: 2023-12-08
#FileName: set3.sh
#URL: http://www.magedu.com
#Description: test
#Copyright(C): 2023 All right
#***************************************************
set -e
echo 123
cd /test2/ #这个目录不存在,如果没有 set -e,则也会删根
rm -rf *
echo 456
#遇到错误行就终止
[root@ubuntu2204 ~]# bash set3.sh
123
set3.sh: line 17: cd: /test2/: No such file or directory

四、Shell脚本案例 

通过shell编程完成,30鸡和兔的头,80鸡和兔的脚,分别有几只鸡,几只兔?

[root@rocky86 ~]# vim rabbit_chook.sh
#!/bin/bash
#
#******************************************************************
#Author:            alex
#QQ:                123456
#Date:              2023-12-10
#FileName:          rabbit_chook.sh
#URL:               https://www.magedu.com/
#Description:       The test script
#Copyright (C):     2023 All rights reserved
#*****************************************************************

count=0
for x in {1..20}; do
    for y in {1..40};do
        let count++
            if [ $[4*x + 2*y] -eq 80 ] && [ $[ x + y ] -eq 30 ]; then
            echo "小白兔="$x"; 小鸡="$y
            break
            fi
    done
done
echo ""
echo "循环次数: " $count
[root@rocky86 ~]# bash rabbit_chook.sh 
小白兔=10; 小鸡=20

循环次数:  780

五、Shell编程基础

结合编程的for循环,条件测试,条件组合,完成批量创建100个用户。

1)for遍历1..100

2)先id判断是否存在

3)用户存在则说明存在,用户不存在则添加用户并说明已添加

[root@localhost ~]# vim create_user.sh
#!/bin/bash
#
#******************************************************************
#Author:            alex
#QQ:                123456
#Date:              2023-12-10
#FileName:          create_user.sh
#URL:               https://www.magedu.com/
#Description:       The test script
#Copyright (C):     2023 All rights reserved
#*****************************************************************

if [ $# -eq 0 ];then
    echo "Usage: `basename $0` user1 user2 ..."
    exit
fi

while [ "$1" ];do
    if id $1 &> /dev/null;then
        echo $1 is exist
    else
        useradd $1
        echo "$1 is created"
    fi
    shift
done

[root@localhost ~]# for i in {1..100};do bash create_user.sh user$i;done
user1 is created
user2 is created
user3 is created
......
user98 is created
user99 is created
user100 is created

六、磁盘存储术语总结

硬盘存储术语 CHS

术 语英文描述
磁 头head一个盘面对应一个磁头
磁 道track盘面上的每一圈就是一个磁道
扇 区sector把每个磁道按512bytes大小再进行划分,这就是扇区,每个磁道上的扇区数量
是不一样的
柱 面cylinder磁头移动的时候,是一起移动的,如果是6个盘面,则6个磁头对应的磁道是一
致的,这就是柱面

CentOS 7 之后,就只显示扇区信息了
CentOS 5 之前版本 Linux 以柱面的整数倍划分分区,CentOS 6 之后可以支持以扇区划分分区

范例:查看CHS信息

#rocky8.6默认只有扇区信息,ubuntu2204同样
[root@rocky86 ~]# fdisk -l /dev/sda
Disk /dev/sda: 200 GiB, 214748364800 bytes, 419430400 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: 0x3475e2b0
Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 2099199 2097152 1G 83 Linux
/dev/sda2 2099200 419430399 417331200 199G 8e Linux LVM

#加参数后可显示更详细信息
[root@rocky86 ~]# fdisk -u=cylinder -l /dev/sda
Disk /dev/sda: 200 GiB, 214748364800 bytes, 419430400 sectors
Geometry: 255 heads, 2 sectors/track, 26108 cylinders
Units: cylinders of 510 * 512 = 261120 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x3475e2b0
Device Boot Start End Cylinders Size Id Type
/dev/sda1 * 5 4117 4113 1G 83 Linux
/dev/sda2 4117 822413 818297 199G 8e Linux LVM

#centos6上默认会显示详细信息
[root@centos6 ~]# fdisk -l /dev/sda
Disk /dev/sda: 214.7 GB, 214748364800 bytes
255 heads, 63 sectors/track, 26108 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0006fc79
Device Boot Start End Blocks Id System
/dev/sda1 * 1 131 1048576 83 Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2 131 12879 102400000 83 Linux
/dev/sda3 12879 19253 51200000 83 Linux
/dev/sda4 19253 26109 55065600 5 Extended
/dev/sda5 19254 19515 2097152 82 Linux swap / Solaris

范例:识别SSD和机械硬盘类型

#1表示机械,0表示SSD
[root@rocky86 ~]# lsblk -d -o name,rota
NAME ROTA
sda 1
sr0 1
nvme0n1 0
nvme0n2 0
[root@rocky86 ~]# ls /sys/block/
nvme0n1 nvme0n2 sda sr0
[root@rocky86 ~]# cat /sys/block/*/queue/rotational
0 0 1 1
[root@rocky86 ~]# cat /sys/block/sda/queue/rotational
1

范例:测速

[root@ubuntu2204 ~]# dd | hdparm -t /dev/sda
/dev/sda:
Timing buffered disk reads: 1854 MB in 3.00 seconds = 617.80 MB/sec

 七、磁盘分区格式MBR和GPT

为什么分区

  • 优化I/O性能
  • 实现磁盘空间配额限制
  • 提高修复速度
  • 隔离系统和程序
  • 安装多个OS
  • 采用不同文件系统

分区方式

两种分区方式:MBR,GPT

MBR分区 

MBR:Master Boot Record,1982年,使用32位表示扇区数,分区不超过2T
划分分区的单位:

  • CentOS 5 之前按整柱面划分
  • CentOS 6 版本后可以按Sector划分

0磁道0扇区:512bytes

  • 446bytes: boot loader 启动相关
  • 64bytes:分区表,其中每16bytes标识一个分区
  • 2bytes: 55AA,标识位

MBR分区中一块硬盘最多有4个主分区,也可以3主分区+1扩展(N个逻辑分区)
MBR分区:主和扩展分区对应的1--4,/dev/sda3,逻辑分区从5开始,/dev/sda5

为什么不能超过4个主分区?
因为在0磁道0扇区上只留了64bytes空间存储分区表信息,而一个分区的关键信息要占用16个字节来存放

为什么单分区不能超2T?
一个分区信息占用16个字节,其中记录分区开始位置的空间为4个字节,记录分区结束位置的空间也是4个字节;
一个字节8位,4个字节是32位,则起始位最小值为32个0,结束位最大值为32个1,
所以一个分区,最大就是2的32次方个扇区,一个扇区512字节,则最大空间是 2^32*2^9 = 2^41 字节;
2^40是T,那2^41就表示不超过2T

硬盘主引导记录MBR由4个部分组成

  • 主引导程序(偏移地址0000H--0088H),它负责从活动分区中装载,并运行系统引导程序
  • 出错信息数据区,偏移地址0089H--00E1H为出错信息,00E2H--01BDH全为0字节
  • 分区表(DPT,Disk Partition Table)含4个分区项,偏移地址01BEH--01FDH,每个分区表项长16个字节,共64字节为分区项1、分区项2、分区项3、分区项4
  • 结束标志字,偏移地址01FE--01FF的2个字节值为结束标志55AA 

范例:查看分区表信息

[root@rocky86 ~]# hexdump -C -n 512 /dev/sda

范例:备份MBR的分区表,并破坏后恢复

#查看分区表
[root@rocky86 ~]# fdisk -l /dev/sda
Disk /dev/sda: 200 GiB, 214748364800 bytes, 419430400 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: 0x5b8e1003
Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 2099199 2097152 1G 83 Linux
/dev/sda2 2099200 419430399 417331200 199G 8e Linux LVM
#备份MBR分区表
[root@rocky86 ~]# dd if=/dev/sda of=/data/dpt.img bs=1 count=64 skip=446
#64字节大小
[root@rocky86 ~]# ll /data/dpt.img
-rw-r--r-- 1 root root 64 Jul 30 11:49 /tmp/dpt.img
#查看具体内容
[root@rocky86 ~]# hexdump -vC /data/dpt.img
#备份到远端
[root@rocky86 ~]# scp /tmp/dpt.img 10.0.0.157:
#破坏MBR分区表
[root@rocky86 ~]# dd if=/dev/zero of=/dev/sda bs=1 count=64 seek=446
64+0 records in
64+0 records out
64 bytes copied, 0.00248682 s, 25.7 kB/s
#再次查看前512字节
[root@rocky86 ~]# hexdump -vC -n 512 /dev/sda
#再次查看分区表,没有分区信息
[root@rocky86 ~]# fdisk -l /dev/sda
Disk /dev/sda: 200 GiB, 214748364800 bytes, 419430400 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: 0x3475e2b0
#但内存中还有相关信息
[root@rocky86 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 200G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 199G 0 part
├─rl-root 253:0 0 70G 0 lvm /
├─rl-swap 253:1 0 2G 0 lvm [SWAP]
└─rl-home 253:2 0 127G 0 lvm /home
sr0 11:0 1 10.5G 0 rom
#重启后无法进系统
[root@rocky86 ~]# reboot
#用光盘启动,进入Rescue mode,选第3项skip to shell
#配置网络
ifconfig ens160 10.0.0.158/24
#或 ip a 10.0.0.158/24 dev ens160
#从远端拿回分区表信息
scp 10.0.0.157:/root/dpt.img .
#恢复MBR分区表
dd if=dpt.img of=/dev/sda bs=1 seek=446
#重启
reboot

GPT分区 

  • GPT:GUID(Globals Unique Identifiers) partition table 支持128个分区,使用64位,支持8Z( 512Byte/block )64Z ( 4096Byte/block)
  • 使用128位UUID(Universally Unique Identifier) 表示磁盘和分区,GPT分区表自动备份在头和尾两份, 并有CRC校验位
  • UEFI (Unified Extensible Firmware Interface 统一可扩展固件接口)硬件支持GPT,使得操作系统可以启动

GPT分区结构分为4个区域:

  • GPT头
  • 分区表
  • GPT分区
  • 备份区域

 范例:ubuntu默认使用gpt分区

root@ubuntu22:~# fdisk -l /dev/sda
Disk /dev/sda: 200 GiB, 214748364800 bytes, 419430400 sectors
Disk model: VMware Virtual S
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: gpt
Disk identifier: D7BA0964-556C-4442-87F5-9B57ACD27E8A
Device Start End Sectors Size Type
/dev/sda1 2048 4095 2048 1M BIOS boot
/dev/sda2 4096 4198399 4194304 2G Linux filesystem
/dev/sda3 4198400 419428351 415229952 198G Linux filesystem

八、管理分区和文件系统 

管理分区 

列出块设备

lsblk [options] [<device> ...]
#常用选项
-a|--all #输出所有设备信息
-b|--bytes #以字节为单位显示设备大小
-d|--nodeps #不显示分区信息
-e|--exclude <list> #以主设备号排除设备
-f|--fs #显示文件系统
-i|--ascii #只使用 ascii 字符输出
-I|--include <list> #仅显示指定的设备
-J|--json #以json格式显示输出
-l|--list #以列表显示
-T|--tree #以树状结构显示,默认项
-m|--perms #显示属主属组及权限
-n|--noheadings #不显示表头
-o|--output <list> #只显示指定列
-O|--output-all #显示所有列
-p|--paths #显示设备全路径
-P|--pairs #以 k=>v 的格式显示输出
-r|--raw #原样输出
-s|--inverse #反向显示关联信息
-S|--scsi #显示scsi设备(small computer system interface
device,小型计算机接口设备)
-t|--topology #显示拓扑信息
#常用字段
NAME #设备名称
MAJ:MIN #主设备号:次设备号
RM #是否是可移动设备
SIZE #设备容量大小
RO #是否是只读设备
TYPE #设备类型
MOUNTPOINT #挂载点
[root@rocky86 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 200G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 199G 0 part
├─rl-root 253:0 0 70G 0 lvm /
├─rl-swap 253:1 0 2G 0 lvm [SWAP]
└─rl-home 253:2 0 127G 0 lvm /home
sr0 11:0 1 10.5G 0 rom
#显示全路径
[root@rocky86 ~]# lsblk -p
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
/dev/sda 8:0 0 200G 0 disk
├─/dev/sda1 8:1 0 1G 0 part /boot
└─/dev/sda2 8:2 0 199G 0 part
├─/dev/mapper/rl-root 253:0 0 70G 0 lvm /
├─/dev/mapper/rl-swap 253:1 0 2G 0 lvm [SWAP]
└─/dev/mapper/rl-home 253:2 0 127G 0 lvm /home
/dev/sr0 11:0 1 10.5G 0 rom
#显示文件系统
[root@rocky86 ~]# lsblk -f
NAME FSTYPE LABEL UUID
MOUNTPOINT
sda
├─sda1 xfs 94a73757-555a-4d2b-8153-f54277c4c50d
/boot
└─sda2 LVM2_member qLmfIa-YvfP-3Du3-dwVG-a0qM-eZRRuP3P80
├─rl-root xfs bd1ab1fd-ee1c-4908-a7b3-e83a170adda9
/
├─rl-swap swap c6f13a3f-a2f3-4ba7-a591-879f476fdd1a
[SWAP]
└─rl-home xfs 22a09cff-b3f2-48c5-b251-c1c4af9b11b7
/home
sr0 iso9660 Rocky-8-6-x86_64-dvd 2022-05-15-21-06-44-00

创建分区命令

fdisk #管理MBR分区
gdisk #管理GPT分区
parted #高级分区操作,可以是交互或非交互方式
partprobe #重新设置内存中的内核分区表版本,适合于除了CentOS 6 以外的其它版本 5,7,8

parted 命令 

注意:parted的操作都是实时生效的,没有交互式确认

格式:

parted [OPTION]... [DEVICE [COMMAND [PARAMETERS]...]...]
#常用选项
-l|--list #显示所有硬盘分区信息
-s|--script #不输出提示信息
#常用子命令
align-check TYPE N #检查分区是否满足对齐(最小|最佳)类型的对齐
方式
help [COMMAND] #显示命令帮助
mklabel|mktable LABEL-TYPE #指定磁盘的分区类型 gpt|msdos(mbr)
mkpart PART-TYPE [FS-TYPE] START END #新建分区,指定分区类型,文件系统,开始结束位
置
name NUMBER NAME #重命名指定分区
print [devices|free|list,all|NUMBER] #显示
quit #退出
rescue START END #空间碎片整理
resizepart NUMBER END #重置分区大小
rm NUMBER #删除指定分区
select DEVICE #选择设备
disk_set FLAG STATE #为设备打标签
disk_toggle [FLAG] #修改flag
set NUMBER FLAG STATE #设置flag
toggle [NUMBER [FLAG]] #修改flag
unit UNIT #设置默认单位, 默认为MB,B|KB|MB|GB|TB
version #显示版本

范例:

#显示所有分区信息
[root@ubuntu2204 ~]# parted -l
......
......
#显示指定磁盘设备分区信息,此磁盘无分区记录,新磁盘
[root@ubuntu2204 ~]# parted /dev/sdb print
Error: /dev/sdb: unrecognised disk label
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags:
#在磁盘上创建GPT分区
[root@ubuntu2204 ~]# parted /dev/sdb mklabel gpt
Information: You may need to update /etc/fstab.
#再次查看
[root@ubuntu2204 ~]# parted /dev/sdb print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
#创建分区
[root@ubuntu2204 ~]# parted /dev/sdb mkpart primary 1 1001
Information: You may need to update /etc/fstab.
#再次查看
[root@ubuntu2204 ~]# parted /dev/sdb print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 1001MB 1000MB primary
#再次创建
[root@ubuntu2204 ~]# parted /dev/sdb mkpart primary 1002 1102
Information: You may need to update /etc/fstab.
#再次查看
[root@ubuntu2204 ~]# parted /dev/sdb print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 1001MB 1000MB primary
2 1002MB 1102MB 99.6MB primary
#删除
[root@ubuntu2204 ~]# parted /dev/sdb rm 2
Information: You may need to update /etc/fstab.
#再次查看
[root@ubuntu2204 ~]# parted /dev/sdb print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 1001MB 1000MB primary

分区工具 fdisk和gdisk

 fdisk

fdisk [options] <disk>
fdisk [options] -l [<disk>]
#类似于fdisk 的GPT分区工具
gdisk [options] [device...]
#常用选项
-b|--sector-size <size> #指定扇区大小,默认512字节
-L|--color[=color] #显示时是否添加颜色(auto|always|never)默认启用颜色
-l|--list #显示
-o|--output <list> #只显示指定列
-u|--units[=<unit>] #设置显示单位 cylinders|sectors,默认sectors
-s|--getsz #显示设备有多少个扇区
-b|--bytes N #以指定的字节大小来计算扇区数量
-t|--type type #只显示指定类型的分区表
-C|--cylinders N #指定柱面数
-H|--heads N #指定磁头数
-S|--sectors N #指定每条磁道的扇区数
#常用子命令
p #输出分区列表
t #更改分区类型
n #创建新分区
d #删除分区
v #校验分区
u #转换单位
w #保存并退出
q #不保存并退出
x #高级功能(专家模式)
#不同类型分区可用的列,配合 -o 选项
gpt: Device Start End Sectors Size Type Type-UUID Attrs Name UUID
dos: Device Start End Sectors Cylinders Size Type Id Attrs Boot End-C/H/S StartC/H/S
bsd: Slice Start End Sectors Cylinders Size Type Bsize Cpg Fsize
sgi: Device Start End Sectors Cylinders Size Type Id Attrs
sun: Device Start End Sectors Cylinders Size Type Id Flags

范例:显示分区列表

#显示所有设备
[root@rocky86 ~]# fdisk -l
#显示指定设备
[root@rocky86 ~]# fdisk -l /dev/sda

范例:显示指定列

[root@rocky86 ~]# fdisk -lo id,size,type /dev/sda
Disk /dev/sda: 200 GiB, 214748364800 bytes, 419430400 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: 0x5b8e1003
Id Size Type
83 1G Linux
8e 199G Linux LVM

范例:查看内核是否已经识别新的分区 

[root@rocky86 ~]# cat /proc/partitions
major minor #blocks name
8 0 209715200 sda
8 1 1048576 sda1
8 2 208665600 sda2
8 16 20971520 sdb
11 0 10950656 sr0
253 0 73400320 dm-0
......

CentOS 7,8 同步分区表

[root@rocky86 ~]# partprobe

CentOS 6 通知内核重新读取硬盘分区表

#新增分区
#partx -a /dev/DEVICE
#kpartx -a /dev/DEVICE -f: force
[root@centos6 ~]# partx -a /dev/sda
#删除分区
#partx -d --nr M-N /dev/DEVICE
[root@centos6 ~]#partx -d --nr 6-8 /dev/sda

范例:非交互式创建分区

[root@rocky86 ~]# echo -e 'n\np\n\n\n+1G\nw' | fdisk /dev/sdb
[root@rocky86 ~]# fdisk /dev/sdb <<EOF
n p +
1G
w
EOF
[root@rocky86 ~]# lsblk /dev/sdb
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdb 8:16 0 20G 0 disk
├─sdb1 8:17 0 1G 0 part
└─sdb2 8:18 0 1G 0 part

gdisk 

gdisk [ -l ] device
#常用子命令
b #备份分区表到指定文件
c #修改分区名
d #删除分区
i #显示分区详细信息
l #列出所有分区类型
n #新建分区
o #创建新的分区表
p #查看分区
q #退出
r #恢复和转换选项,非专业人士勿用
s #排序
t #修改分区类型,默认 8300,表示普通分区
v #检测硬盘是否有问题
w #保存退出
x #额外功能,专家模式
? #显示帮助

文件系统 

文件系统概念

文件系统是操作系统用于明确存储设备或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。
操作系统中负责管理和存储文件信息的软件结构称为文件管理系统,简称文件系统
从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,安全控制,日志,压缩,加密等。

查看当前内核支持的文件系统:

#rocky8.6
[root@rocky86 ~]# ls /lib/modules/`uname -r`/kernel/fs
binfmt_misc.ko.xz cifs ext4 fuse jbd2 nfs nls
squashfs
cachefiles cramfs fat gfs2 lockd nfs_common overlayfs
udf
ceph dlm fscache isofs mbcache.ko.xz nfsd pstore
xfs

#ubuntu22.04
root@ubuntu22:~# ls /lib/modules/`uname -r`/kernel/fs
9p bfs coda f2fs hfs ksmbd nfsd omfs
quota ubifs
adfs binfmt_misc.ko cramfs fat hfsplus lockd nilfs2 orangefs
reiserfs udf
affs btrfs dlm freevxfs hpfs minix nls overlayfs
romfs ufs
afs cachefiles efs fscache isofs netfs ntfs pstore
shiftfs.ko vboxsf
autofs ceph erofs fuse jffs2 nfs ntfs3 qnx4
smbfs_common xfs
befs cifs exfat gfs2 jfs nfs_common ocfs2 qnx6
sysv zonefs

查看当前系统可用的文件系统:

#rocky8.6
[root@rocky86 ~]# cat /proc/filesystems
nodev sysfs
nodev tmpfs
nodev bdev
nodev proc
nodev cgroup
nodev cgroup2
nodev cpuset
nodev devtmpfs
nodev configfs
nodev debugfs
nodev tracefs
nodev securityfs
nodev sockfs
nodev bpf
nodev pipefs
nodev ramfs
nodev hugetlbfs
nodev devpts
nodev autofs
nodev pstore
nodev mqueue
fuseblk
nodev fuse
nodev fusectl
xfs
nodev rpc_pipefs

#ubuntu22.04
root@ubuntu22:~# cat /proc/filesystems
nodev sysfs
nodev tmpfs
nodev bdev
nodev proc
nodev cgroup
nodev cgroup2
nodev cpuset
nodev devtmpfs
nodev configfs
nodev debugfs
nodev tracefs
nodev securityfs
nodev sockfs
nodev bpf
nodev pipefs
nodev ramfs
nodev hugetlbfs
nodev devpts
ext3
ext2
ext4
squashfs
vfat
nodev ecryptfs
fuseblk
nodev fuse
nodev fusectl
nodev mqueue
nodev pstore
btrfs
nodev autofs

当前系统支持的文件系统和当前系统可用的文件系统是两回事,modules 中的文件系统在编译时选择了才是可用的,而可用的文件系统包含了默认支持的文件系统,如果需要使用某个文件系统,而该文件系统又不在proc 中,则需要重新编译内核;

各种文件系统:

https://en.wikipedia.org/wiki/Comparison_of_file_systems

man 5 fs    #查看帮助

文件系统类型 

Linux 常用文件系统

文件系统备注
ext2Extended file system 适用于那些分区容量不是太大,更新也不频繁的情况,例如
/boot 分 区
ext3ext2 的改进版本,其支持日志功能,能够帮助系统从非正常关机导致的异常中恢复
ext4ext 文件系统的最新版。有很多新的特性,包括纳秒级时间戳、巨型文件 (16TB)、最
大1EB的文件系统,以及速度的提升
xfsSGI,支持最大8EB的文件系统
swap交换分区专用的文件系统
iso9660光盘文件系统
btrFSOracle公司开发
reiserFS

 Windows 常用文件系统

文件系统备注
FAT32最多只能支持16TB的文件系统和4GB的文件
NTFS最多只能支持16EB的文件系统和16EB的文件
extFAT

Unix 常用文件系统

文件系统备注
FFS(fast)
UFS(unix)UFS是UNIX文件系统的简称,几乎是大部分UNIX类操作系统默认的基于磁盘的文件
系统
JFS2

网络文件系统

文件系统备注
NFSNetwork File System,即网络文件系统
CIFS

集群文件系统

文件系统备注
GFS2基于X86_64,最大文件系统可到100TB
OCFS2(oracle)

分布式文件系统

文件系统备注
fastdFS
ceph不仅仅是一个文件系统,还是一个有企业级功能的对象存储生态环境
mooseFS
mogileFS
glusterFS
Lustre

RAW
裸文件系统,未经处理或者未经格式化产生的文件系统
常用的文件系统特性:
FAT32
最多只能支持16TB的文件系统和4GB的文件
NTFS
最多只能支持16EB的文件系统和16EB的文件

EXT3 

  • 最多只能支持32TB的文件系统和2TB的文件,实际只能容纳2TB的文件系统和16GB的文件
  • Ext3目前只支持32000个子目录
  • Ext3文件系统使用32位空间记录块数量和 inode数量
  • 当数据写入到Ext3文件系统中时,Ext3的数据块分配器每次只能分配一个4KB的块

EXT4

  • EXT4是Linux系统下的日志文件系统,是EXT3文件系统的后继版本
  • Ext4的文件系统容量达到1EB,而支持单个文件则达到16TB
  • 理论上支持无限数量的子目录
  • Ext4文件系统使用64位空间记录块数量和 inode数量
  • Ext4的多块分配器支持一次调用分配多个数据块
  • 修复速度更快

XFS

  • 根据所记录的日志在很短的时间内迅速恢复磁盘文件内容
  • 用优化算法,日志记录对整体文件操作影响非常小
  • 是一个全64-bit的文件系统,最大可以支持8EB的文件系统,而支持单个文件则达到8EB
  • 能以接近裸设备I/O的性能存储数据

文件系统的组成部分 

  • 内核中的模块:ext4,xfs,vfat
  • Linux的虚拟文件系统:VFS
  • 用户空间的管理工具:mkfs.ext4,mkfs.xfs,mkfs.vfat

文件系统选择管理 

创建文件系统 

mkfs

mkfs [options] [-t <type>] [fs-options] <device> [<size>]
#常用选项
-t|--type=model #指定文件系统类型 (ext2|ext3|ext4|xfs),默认 ext2
-b #指定块 block 大小 (1024|2048|4096)
-L LABEL #设置卷标
-V|--verbose #显示创建过程
-j #同 -t ext3
-i N #为数据空间中每多少个字节创建一个inode;不应该小于block
大小
-N N #指定分区中创建多少个inode
-I N #一个inode记录占用的磁盘空间大小,128---4096
-m N #默认5%,为管理人员预留空间占总空间的百分比
-O FEATURE[,...] #启用指定特性
-O ^FEATURE #关闭指定特性

范例:

#创建ext4 文件系统
#mkfs.ext4 /dev/sdc1 等同于 mkfs -t ext4 /dev/sdc1
[root@ubuntu2204 ~]# mkfs.ext4 /dev/sdc1
mke2fs 1.46.5 (30-Dec-2021)
Creating filesystem with 524288 4k blocks and 131072 inodes
Filesystem UUID: e55d9611-63c5-43dd-a6b3-fe6409778834
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done

#创建xfs文件系统
[root@ubuntu2204 ~]# mkfs.xfs /dev/sdc2
meta-data=/dev/sdc2 isize=512 agcount=4, agsize=196608 blks
         = sectsz=512 attr=2, projid32bit=1
         = crc=1 finobt=1, sparse=1, rmapbt=0
         = reflink=1 bigtime=0 inobtcount=0
data     = bsize=4096 blocks=786432, imaxpct=25
         = sunit=0 swidth=0 blks
naming   =version 2 bsize=4096 ascii-ci=0, ftype=1
log      =internal log bsize=4096 blocks=2560, version=2
         = sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0

范例:查看

#查看指定设备
[root@ubuntu2204 ~]# lsblk -f /dev/sdc
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE%
MOUNTPOINTS
sdc
├─sdc1 ext4 1.0 e55d9611-63c5-43dd-a6b3-fe6409778834
└─sdc2 xfs b2d34757-f593-46ce-a8e6-d1009eb71fdc

#查看所有设备
[root@rocky86 ~]# lsblk -f
NAME FSTYPE LABEL UUID
MOUNTPOINT
sda
├─sda1 xfs 94a73757-555a-4d2b-8153-f54277c4c50d
/boot
└─sda2 LVM2_member qLmfIa-YvfP-3Du3-dwVG-a0qM-eZRRuP3P80
├─rl-root xfs bd1ab1fd-ee1c-4908-a7b3-e83a170adda9
/
├─rl-swap swap c6f13a3f-a2f3-4ba7-a591-879f476fdd1a
[SWAP]
└─rl-home xfs 22a09cff-b3f2-48c5-b251-c1c4af9b11b7
/home
sdb
├─sdb1
├─sdb2
├─sdb5
└─sdb6
sdc
├─sdc1 ext4 a7751b8e-da27-447e-9466-79127e0850af
└─sdc2 xfs 205ecdf1-1f0e-495d-a1ab-2f74b6ab98a0
sr0 iso9660 Rocky-8-6-x86_64-dvd 2022-05-15-21-06-44-00

#df 只能查看己挂载的设备
[root@ubuntu2204 ~]# df -l
Filesystem 1K-blocks Used Available Use% Mounted on
tmpfs 198824 1340 197484 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 101590008 6261024 90122356 7% /
tmpfs 994116 0 994116 0% /dev/shm
tmpfs 5120 0 5120 0% /run/lock
/dev/sda2 1992552 255260 1616052 14% /boot
tmpfs 198820 4 198816 1% /run/user/0

mke2fs
ext系列文件系统专用管理工具

mke2fs [OPTION]... DEVICE
#常用选项
-t #指定文件系统类型 {ext2|ext3|ext4|xfs}
-b #指定块大小{1024|2048|4096}
-L LABEL #设置卷标
-j #同 -t ext3,mkfs.ext3|mkfs -t ext3|mke2fs -
j|mke2fs -t ext3
-i N #为数据空间中每多少个字节创建一个inode 不应该小于
block大小
-N N #指定分区中创建多少个inode
-I N #一个inode记录占用的磁盘空间大小,128---4096
-m N #默认5%,为管理人员预留空间占总空间的百分比
-O FEATURE[,...] #启用指定特性
-O ^FEATURE #关闭指定特性
查看和管理分区信息 

blkid
查看块设备属性信息

blkid [OPTION]... [DEVICE]
#常用选项
-U UUID #根据指定的UUID来查找对应的设备
-L LABEL #根据指定的LABEL来查找对应的设备

范例:

#显示所有
[root@ubuntu2204 ~]# blkid
/dev/sr0: BLOCK_SIZE="2048" UUID="2022-04-21-06-14-25-00" LABEL="Ubuntu-Server
22.04 LTS amd64" TYPE="iso9660" PTTYPE="PMBR"
/dev/mapper/ubuntu--vg-ubuntu--lv: UUID="1966a290-5acc-42e2-ac89-01c53605ad67"
BLOCK_SIZE="4096" TYPE="ext4"
/dev/sda2: UUID="195992f6-95be-4629-b331-8fb09cf99819" BLOCK_SIZE="4096"
TYPE="ext4" PARTUUID="33d3d630-668e-4ed0-adc9-a1738194fb6e"
/dev/sda3: UUID="91MDjY-MTWb-FpTD-Mint-34Mi-MtlY-q5B4MX" TYPE="LVM2_member"
PARTUUID="2eecafb8-2084-4b68-a30e-32ad0cb85cc0"
/dev/loop1: TYPE="squashfs"
/dev/sdb1: PARTLABEL="primary" PARTUUID="05759b66-4eeb-42ae-b9e8-ad41b95c132c"
/dev/loop4: TYPE="squashfs"
/dev/loop2: TYPE="squashfs"
/dev/loop0: TYPE="squashfs"
/dev/sdc2: UUID="b2d34757-f593-46ce-a8e6-d1009eb71fdc" BLOCK_SIZE="512"
TYPE="xfs" PARTUUID="a6ea333f-02"
/dev/sdc1: UUID="e55d9611-63c5-43dd-a6b3-fe6409778834" BLOCK_SIZE="4096"
TYPE="ext4" PARTUUID="a6ea333f-01"
/dev/sda1: PARTUUID="8246d3f4-9d83-491d-b3fd-2c556d3b652c"
#查询
[root@ubuntu2204 ~]# blkid -U "e55d9611-63c5-43dd-a6b3-fe6409778834"
/dev/sdc1

e2label
管理ext系列文件系统的LABEL

e2label DEVICE [LABEL]

findfs
查找分区

findfs [options] {LABEL,UUID,PARTUUID,PARTLABEL}=<value>

范例:

[root@ubuntu2204 ~]# findfs UUID=b2d34757-f593-46ce-a8e6-d1009eb71fdc
/dev/sdc2
[root@ubuntu2204 ~]# findfs LABEL='Ubuntu-Server 22.04 LTS amd64'
/dev/sr0

tune2fs
重新设定ext系列文件系统可调整参数的值

tune2fs [OPTION]... [DEVICE]
#常用选项
-l #查看指定文件系统信息
-L LABEL #修改卷标
-m N #修预留给管理员的空间百分比
-j #将ext2升级为ext3
-O #文件系统属性启用或禁用, -O ^has_journal
-o #调整文件系统的默认挂载选项,-o ^acl
-U UUID #修改UUID号

范例:

[root@ubuntu2204 ~]# tune2fs -l /dev/sdc1
tune2fs 1.46.5 (30-Dec-2021)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: e55d9611-63c5-43dd-a6b3-fe6409778834
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
......
......

dumpe2fs
显示ext文件系统信息,将磁盘块分组管理

dumpe2fs [OPTION]... [DEVICE]

范例:

[root@ubuntu2204 ~]# dumpe2fs /dev/sdc1
dumpe2fs 1.46.5 (30-Dec-2021)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: e55d9611-63c5-43dd-a6b3-fe6409778834
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
......
......
#查看超级块信息
[root@ubuntu2204 ~]# dumpe2fs -h /dev/sdc1
dumpe2fs 1.46.5 (30-Dec-2021)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: e55d9611-63c5-43dd-a6b3-fe6409778834
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
......
......

xfs_info
显示已挂载的 xfs 文件系统信息

xfs_info mountpoint|devname

范例:

[root@ubuntu2204 ~]# xfs_info /dev/sdc2
meta-data=/dev/sdc2 isize=512 agcount=4, agsize=196608 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1 bigtime=0 inobtcount=0
data = bsize=4096 blocks=786432, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0

超级块和INODE TABLE 

块组描述符表(GDT)
ext文件系统每一个块组信息使用32字节描述,这32个字节称为块组描述符,所有块组的块组描述符组成块组描述符表GDT(group descriptor table)。虽然每个块组都需要块组描述符来记录块组的信息和属性元数据,但是不是每个块组中都存放了块组描述符。将所有块组的块组信息组成一个GDT保存,并将该GDT存放于某些块组中,类似存放superblock和备份superblock的块。

文件系统检测和修复 

文件系统故障常发生于死机或者非正常关机之后,挂载为文件系统标记为“no clean”
注意:一定不要在挂载状态下执行下面命令修复

fsck
fsck: File System Check

fsck [options] -- [fs-options] [<filesystem> ...]
#常用选项
-a #自动修复
-r #交互式修复错误

范例:

[root@ubuntu2204 ~]# fsck.ext4 /dev/sdc1
e2fsck 1.46.5 (30-Dec-2021)
/dev/sdc1: clean, 11/131072 files, 26156/524288 blocks
[root@ubuntu2204 ~]# fsck -t ext4 /dev/sdc1
fsck from util-linux 2.37.2
e2fsck 1.46.5 (30-Dec-2021)
/dev/sdc1: clean, 11/131072 files, 26156/524288 blocks

e2fsck
ext系列文件专用的检测修复工具

e2fsck [options] -- [fs-options] [<filesystem> ...]
#常用选项
-y #自动回答为yes
-f #强制修复
-p #自动进行安全的修复文件系统问题

xfs_repair
xfs文件系统专用检测修复工具

xfs_repair [options] device
#常用选项
-f #修复文件,而设备
-n #只检查
-d #允许修复只读的挂载设备,在单用户下修复 / 时使用,然后立即reboot

范例:修复破坏的ext文件系统

[root@ubuntu2204 ~]# mount /dev/sdc1 /mnt
[root@ubuntu2204 ~]# cp /etc/fstab /mnt/f1
[root@ubuntu2204 ~]# cp /etc/fstab /mnt/f2
[root@ubuntu2204 ~]# ls /mnt/
f1 f2 lost+found
[root@ubuntu2204 ~]# dd if=/dev/zero of=/dev/sdc1 bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00302592 s, 347 MB/s
[root@ubuntu2204 ~]# ls /mnt/
[root@ubuntu2204 ~]# tune2fs -l /dev/sdc1
tune2fs 1.46.5 (30-Dec-2021)
tune2fs: Bad magic number in super-block while trying to open /dev/sdc1

[root@ubuntu2204 ~]# df
Filesystem 1K-blocks Used
Available Use% Mounted on
tmpfs 198824 1340
197484 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 101590008 6261024
90122356 7% /
tmpfs 994116 0
994116 0% /dev/shm
tmpfs 5120 0
5120 0% /run/lock
/dev/sda2 1992552 255260
1616052 14% /boot
tmpfs 198820 4
198816 1% /run/user/0
/dev/sdc1 73786976294838101864 73786976294836109344
1976136 100% /mnt
[root@ubuntu2204 ~]# umount /mnt

[root@ubuntu2204 ~]# e2fsck /dev/sdc1
e2fsck 1.46.5 (30-Dec-2021)
ext2fs_open2: Bad magic number in super-block
e2fsck: Superblock invalid, trying backup blocks...
Superblock needs_recovery flag is clear, but journal has data.
Recovery flag not set in backup superblock, so running journal anyway.
/dev/sdc1: recovering journal
Resize inode not valid. Recreate<y>? yes
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Block bitmap differences: +(98304--98560) +(163840--164096) +(229376--229632) +
(294912--295168)
Fix<y>? yes
Free blocks count wrong for group #0 (24280, counted=24281).
Fix<y>? yes
Free blocks count wrong for group #1 (32511, counted=32509).
Fix<y>? yes
Free blocks count wrong (498131, counted=498130).
Fix<y>? yes
Free inodes count wrong for group #0 (8181, counted=8179).
Fix<y>? yes
Free inodes count wrong (131061, counted=131059).
Fix<y>? yes
Padding at end of inode bitmap is not set. Fix<y>? yes
/dev/sdc1: ***** FILE SYSTEM WAS MODIFIED *****
/dev/sdc1: 13/131072 files (0.0% non-contiguous), 26158/524288 blocks

[root@ubuntu2204 ~]# tune2fs -l /dev/sdc1
tune2fs 1.46.5 (30-Dec-2021)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: e55d9611-63c5-43dd-a6b3-fe6409778834
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
[root@ubuntu2204 ~]# mount /dev/sdc1 /mnt
[root@ubuntu2204 ~]# ls /mnt/
f1 f2 lost+found

[root@ubuntu2204 ~]# cat /mnt/f1
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation
/dev/disk/by-id/dm-uuid-LVM-
2DfhG2JAeOckxicJorCIykZWj5F57OAw1wUxIh2DKVkhusX3fhgEVlJJIPV3tnGn / ext4 defaults
0 1
# /boot was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/195992f6-95be-4629-b331-8fb09cf99819 /boot ext4 defaults 0 1
/swap.img none swap sw 0 0

挂载 

挂载:将额外文件系统与根文件系统某现存的目录建立起关联关系,进而使得此目录做为其它文件访问入口的行为
卸载:为解除此关联关系的过程
把设备关联挂载点:mount Point
挂载点下原有文件在挂载完成后会被临时隐藏,因此,挂载点目录一般为空 进程正在使用中的设备无法被卸载

挂载文件系统 mount

格式:

mount [-lhV]
mount -a [options]
mount [options] [--source] <source> | [--target] <directory>
mount [options] <source> <directory>
mount <operation> <mountpoint> [<target>]

device:指明要挂载的设备

  • 设备文件:例如:/dev/sda5
  • 卷标:-L 'LABEL',例如 -L 'MYDATA'
  • UUID: -U 'UUID':例如 -U '0c50523c-43f1-45e7-85c0-a126711d406e'
  • 伪文件系统名称:proc,sysfs,devtmpfs,configfs

mountpoint:挂载点目录必须事先存在,建议使用空目录 

挂载规则:

  • 一个挂载点同一时间只能挂载一个设备
  • 一个挂载点同一时间挂载了多个设备,只能看到最后一个设备的数据,其它设备上的数据将被隐藏
  • 一个设备可以同时挂载到多个挂载点
  • 通常挂载点一般是已存在空的目录

mount 常用命令选项

-a|--all #自动挂载所有支持自动挂载的设备(定义在了/etc/fstab
文件中,且挂载选项中有auto功能)
-B|--bind #绑定目录到另一个目录上
-c|--no-canonicalize #不对路径规范化
-f|--fake #空运行;跳过 mount(2) 系统调用
-F|--fork #对每个设备禁用 fork,配合-a 选项一起使用
-T|--fstab path #指定写文件,默认 /etc/fstab
-i|--internal-only #不调用 mount.<type> 辅助程序
-l|--show-labels #显示文件系统的 labels
-n|--no-mtab #不更新/etc/mtab,mount不可见
-o|--options o1,o2 #挂载选项列表,以英文逗号分隔
-O|--test-opts o1,o2 #限制文件系统集合(和 -a 选项一起使用)
-r|--read-only #以只读方式挂载文件系统(同 -o ro)
-t|--types #指定要挂载的设备上的文件系统类型,如:ext4,xfs
--source device #指明源(路径、标签、uuid)
--target mountpoint #指明挂载点
-v|--verbose #显示过程
-w|--rw|--read-write #以读写方式挂载文件系统(默认)
-L LABEL #以卷标指定挂载设备
-U UUID #以UUID指定要挂载的设备

#-o选项值
async #异步模式,内存更改时,写入缓存区buffer,过一段时间再写
到磁盘中,效率高,但不安全
sync #同步模式,内存更改时,同时写磁盘,安全,但效率低下
atime/noatime #包含目录和文件
diratime/nodiratime #目录的访问时间戳
auto/noauto #是否支持开机自动挂载,是否支持-a选项
exec/noexec #是否支持将文件系统上运行应用程序
dev/nodev #是否支持在此文件系统上使用设备文件
suid/nosuid #是否支持suid和sgid权限
remount #重新挂载
ro/rw #只读/读写
user/nouser #是否允许普通用户挂载此设备,/etc/fstab使用
acl/noacl #启用此文件系统上的acl功能
loop #使用loop设备
_netdev #当网络可用时才对网络资源进行挂载,如:NFS文件系统
defaults #相当于rw, suid, dev, exec, auto, nouser,
async

#--source 选项值
-L|--label label #同 LABEL=label
-U|--uuid uuid #同 UUID=uuid
LABEL=label #用label值指定设备
UUID=uuid #用uuid值指定设备
PARTLABEL=label #按PARTLABEL值指定设备
PARTUUID=uuid #按PARTUUID值指定设备
device #按路径指定设备
directory #绑定式挂载的挂载点(参阅 --bind/rbind)
file #用于设置回环设备的常规文件

范例:

[root@rocky86 ~]# lsblk /dev/sdc -f
NAME FSTYPE LABEL UUID MOUNTPOINT
sdc
├─sdc1 ext4 a7751b8e-da27-447e-9466-79127e0850af
└─sdc2 xfs 205ecdf1-1f0e-495d-a1ab-2f74b6ab98a0
[root@ubuntu2204 ~]# lsblk /dev/sdc -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE%
MOUNTPOINTS
sdc
├─sdc1 ext4 1.0 e55d9611-63c5-43dd-a6b3-fe6409778834
└─sdc2 xfs b2d34757-f593-46ce-a8e6-d1009eb71fdc
[root@ubuntu2204 ~]# mkdir /sdc{1,2}
[root@ubuntu2204 ~]# mount /dev/sdc1 /sdc1
#只读挂载
[root@ubuntu2204 ~]# mount --source /dev/sdc2 -o ro /sdc2
[root@ubuntu2204 ~]# lsblk /dev/sdc -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE%
MOUNTPOINTS
sdc
├─sdc1 ext4 1.0 e55d9611-63c5-43dd-a6b3-fe6409778834 1.8G 0%
/sdc1
└─sdc2 xfs b2d34757-f593-46ce-a8e6-d1009eb71fdc 3G 0%
/sdc2
#写测试
[root@ubuntu2204 ~]# cp /etc/fstab /sdc1/
[root@ubuntu2204 ~]# cp /etc/fstab /sdc2/
cp: cannot create regular file '/sdc2/fstab': Read-only file system

卸载文件系统 umount 

卸载时:可使用设备,也可以使用挂载点

格式:

umount [-hV]
umount -a [options]
umount [options] <source> | <directory>

范例:

[root@ubuntu2204 ~]# lsblk /dev/sdc -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE%
MOUNTPOINTS
sdc
├─sdc1 ext4 1.0 e55d9611-63c5-43dd-a6b3-fe6409778834 1.8G 0%
/sdc1
└─sdc2 xfs b2d34757-f593-46ce-a8e6-d1009eb71fdc 3G 0%
/sdc2
#设备卸载
[root@ubuntu2204 ~]# umount /dev/sdc1
#挂载点卸载
[root@ubuntu2204 ~]# umount /sdc2

#再次查看挂载情况
[root@ubuntu2204 ~]# lsblk /dev/sdc -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE%
MOUNTPOINTS
sdc
├─sdc1 ext4 1.0 e55d9611-63c5-43dd-a6b3-fe6409778834
└─sdc2 xfs b2d34757-f593-46ce-a8e6-d1009eb71fdc

查看挂载情况 

查看挂载

mount #通过mount命令查看
cat /etc/mtab #通过查看/etc/mtab文件显示当前已挂载的所有设备
cat /proc/mounts #查看内核追踪到的已挂载的所有设备

范例:

[root@ubuntu2204 ~]# mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
udev on /dev type devtmpfs
(rw,nosuid,relatime,size=935836k,nr_inodes=233959,mode=755,inode64)
devpts on /dev/pts type devpts
(rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
......

[root@ubuntu2204 ~]# cat /etc/mtab
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
udev /dev devtmpfs
rw,nosuid,relatime,size=935836k,nr_inodes=233959,mode=755,inode64 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
......

[root@ubuntu2204 ~]# cat /proc/mounts
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
udev /dev devtmpfs
rw,nosuid,relatime,size=935836k,nr_inodes=233959,mode=755,inode64 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
......

查看挂载点情况

findmnt [options]
findmnt [options] <device> | <mountpoint>
findmnt [options] <device> <mountpoint>
findmnt [options] [--source <device>] [--target <path> | --mountpoint <dir>]

范例:

#默认查看整个系统挂载树
[root@ubuntu2204 ~]# findmnt
......
#查看指定设备或挂载点
[root@ubuntu2204 ~]# findmnt /dev/sdc1
TARGET SOURCE FSTYPE OPTIONS
/sdc1 /dev/sdc1 ext4 rw,relatime

查看正在访问指定文件系统的进程

lsof MOUNT_POINT
fuser -v MOUNT_POINT

终止所有在正访问指定的文件系统的进程

fuser -km MOUNT_POINT

持久挂载 

将挂载保存到 /etc/fstab 中可以下次开机时,自动启用挂载

#/etc/fstab格式帮助
man 5 fstab

每行定义一个要挂载的文件系统,,其中包括共 6 项

  • 要挂载的设备或伪文件系统设备文件(LABEL=label | UUID=uuid | /dev/sda1)
  • 挂载点:必须是事先存在的目录
  • 文件系统类型:ext4,xfs,iso9660,nfs,none
  • 挂载选项:defaults ,acl,bind,ro,rw 等
  • 转储频率:0 不做备份;1 每天转储;2 每隔一天转储
  • fsck检查的文件系统的顺序:0 不自检;1 首先自检,一般只有rootfs才用;2 非rootfs使用

[root@rocky86 ~]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sun Jul 3 12:05:30 2022
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
/dev/mapper/rl-root / xfs defaults 0 0
UUID=94a73757-555a-4d2b-8153-f54277c4c50d /boot xfs defaults 0 0
/dev/mapper/rl-home /home xfs defaults 0 0
/dev/mapper/rl-swap none swap defaults 0 0
[root@ubuntu2204 ~]# cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation
/dev/disk/by-id/dm-uuid-LVM-
2DfhG2JAeOckxicJorCIykZWj5F57OAw1wUxIh2DKVkhusX3fhgEVlJJIPV3tnGn / ext4 defaults
0 1
# /boot was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/195992f6-95be-4629-b331-8fb09cf99819 /boot ext4 defaults 0 1
/swap.img none swap sw 0 0

添加新的挂载项,需要执行下面命令生效
此命令只针对文件新增行或删除行有效,如果在中间修改了挂载选项,则此命令无效

mount -a

修改文件前后对比

[root@ubuntu2204 ~]# df;mount -a;echo;df

如果 /etc/fstab 中的分区UUID出错,则会无法进系统
解决方案:
centos7,centos8 会自动进入 emergency 模式,输入root密码后,再修改 /etc/fstab,然后重启即可
centos6 中除了修改为正确之外,还可以将 /etc/fstab 文件中错误行最后一项设置为0,即不检查

重新挂载

修改了 /etc/fstab 文件中的挂载规则,无法通过 mount -a 生效,要执行执行挂载

mount -o remount MOUNTPOINT

处理交换文件和分区 

swap 介绍 

swap交换分区是系统RAM的补充,swap 分区支持虚拟内存。当没有足够的 RAM 保存系统处理的数据时会将数据写入 swap 分区,当系统缺乏 swap 空间时,内核会因 RAM 内存耗尽而终止程。
配置过多 swap 空间会造成存储设备处于分配状态但闲置,造成浪费,过多 swap 空间还会掩盖内存泄露。
注意:为优化性能,可以将swap 分布存放,或高性能磁盘存放

Redhat 官方推荐推荐系统 swap 空间

https://access.redhat.com/documentation/zhcn/red_hat_enterprise_linux/7/html/installation_guide/sect-disk-partitioningsetup-ppc#sect-recommended-partitioning-scheme-ppc
系统中的 RAM 量推荐的 swap 空间允许休眠的建议 swap 空间大小
低于 2 GBRAM 量的2倍数RAM 容量的三倍
2 GB - 8 GB等于 RAM 量RAM 量的倍数
8 GB - 64 GB4 GB 到 RAM 容量的 0.5 倍RAM 容量的 1.5 倍
8 GB - 64 GB独立负载(至少 4GB)不建议使用休眠功能

范例:

[root@ubuntu2204 ~]# free -h
total used free shared buff/cache available
Mem: 1.9Gi 347Mi 896Mi 1.0Mi 697Mi 1.4Gi
Swap: 2.0Gi 0B 2.0Gi
[root@ubuntu2204 ~]# dd if=/dev/zero of=/dev/null bs=30G count=1
dd: memory exhausted by input buffer of size 32212254720 bytes (30 GiB)
#这里文件大小虽然超过了,但有SWAP空间,所以可以执行成功
[root@ubuntu2204 ~]# dd if=/dev/zero of=/dev/null bs=3G count=1
0+1 records in
0+1 records out
2147479552 bytes (2.1 GB, 2.0 GiB) copied, 7.40064 s, 290 MB/s

交换分区实现过程 

1. 创建交换分区或者文件
2. 使用mkswap写入特殊签名
3. 在/etc/fstab文件中添加适当的条目
4. 使用swapon -a 激活交换空间 

启用swap分区

swapon [options] [<spec>]
#常用选项
-a|--all #激活 /etc/fstab 中的所有交换区
-d|--discard[=policy] #根据条件禁用(once|pages)
-e|--ifexists #自动跳过不存在的设备而不提示
-f|--fixpgsz #必要时重新初始化交换区
-o|--options list #指定选项,swapon -o pri=1,discard=pages,nofail
/dev/sda2
-p|--priority N #指定交换设备的优先级(-1到32767),值越大优先级越高,也可
在/etc/fstab第4列指定pri=value
-s|--summary #显示已使用交换设备的摘要
--show[=columns] #以可自定义的表格形式打印摘要 swapon --show|swapon
--show=NAME,TYPE
--noheadings #不打印表头,配合 --show 选项
--raw #使用原生输出格式,配合 --show 选项
--bytes #在 --show 输出中以字节数显示交换区大小
-v|--verbose #显示详细信息

#<spec> 参数:
-L label #同 LABEL=label
-U uuid #同 UUID=uuid
LABEL=label #按交换区标签指定设备
UUID=uuid #按交换区 UUID 指定设备
PARTLABEL=label #按分区标签指定设备
PARTUUID=uuid #按分区 UUID 指定设备
device #要使用设备的名称
filename #要使用文件的名称

#可显示列
NAME #设备文件或分区路径
TYPE #设备的类型
SIZE #交换区大小
USED #已使用字节数
PRIO #交换优先级
UUID #uuid
LABEL #label

禁用swap分区

swapoff [options] [<spec>]
#常用选项
-a|--all #禁用 /proc/swaps 中的所有交换区
-v|--verbose #显示过程

#spec 参数
-L label #要使用设备的标签
-U uuid #要使用设备的 UUID
LABEL=label #要使用设备的标签
UUID=uuid #要使用设备的 UUID
device #要使用设备的名称
filename #要使用文件的名称

创建swap分区

#先创建分区,选择swap类型
#再创建swap文件系统
[root@ubuntu2204 ~]# mkswap /dev/sdc3
Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=e08d9c52-98f2-4fed-8f19-5a890bece201
#查看
[root@ubuntu2204 ~]# blkid /dev/sdc3
/dev/sdc3: UUID="e08d9c52-98f2-4fed-8f19-5a890bece201" TYPE="swap"
PARTUUID="a6ea333f-03"
#修改/etc/fstab文件,添加swap行
#禁用,再次启用
[root@ubuntu2204 ~]# swapoff -a
[root@ubuntu2204 ~]# swapon -a
#查看,比原来多2GB swap空间
[root@ubuntu2204 ~]# free -h
total used free shared buff/cache available
Mem: 1.9Gi 295Mi 1.5Gi 1.0Mi 112Mi 1.5Gi
Swap: 4.0Gi 0B 4.0Gi
#查看内存
[root@ubuntu2204 ~]# cat /proc/swaps
Filename Type Size Used Priority
/swap.img file 2097148 0 -2
/dev/sdc3 partition 2097148 0 -3

查看swap分区
Priority越大,优先级越高,会被优先使用

[root@ubuntu2204 ~]# swapon -s
Filename Type Size Used Priority
/swap.img file 2097148 0 -2
/dev/sdc3 partition 2097148 0 -3
[root@ubuntu2204 ~]# cat /proc/swaps
Filename Type Size Used Priority
/swap.img file 2097148 0 -2
/dev/sdc3 partition 2097148 0 -3

修改swap优先级
可以指定swap分区0到32767的优先级,值越大优先级越高
如果用户没有指定,那么核心会自动给swap指定一个优先级,这个优先级从-1开始,每加入一个新的 没有用户指定优先级的swap,会给这个优先级减一
添加的swap的缺省优先级比较高,除非用户自己指定一个优先级,而用户指定的优先级(是正数)永远 高于核心缺省指定的优先级(是负数)

[root@rocky86 ~]# swapon -s
Filename Type Size Used Priority
/dev/dm-1 partition 2125820 0 -2
/dev/sdb7 partition 2097148 0 -3
[root@ubuntu2204 ~]# cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation
/dev/disk/by-id/dm-uuid-LVM-
2DfhG2JAeOckxicJorCIykZWj5F57OAw1wUxIh2DKVkhusX3fhgEVlJJIPV3tnGn / ext4 defaults
0 1
# /boot was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/195992f6-95be-4629-b331-8fb09cf99819 /boot ext4 defaults 0 1
/swap.img none swap sw 0 0
/dev/sdc1 /sdc1 ext4 defaults 0 0
/dev/sdc3 none swap sw,pri=123 0 0
[root@ubuntu2204 ~]# swapoff -a;swapon -a
[root@ubuntu2204 ~]# swapon -s
Filename Type Size Used Priority
/swap.img file 2097148 0 -2
/dev/sdc3 partition 2097148 0 123

以文件作为swap分区

#创建文件
[root@ubuntu2204 ~]# dd if=/dev/zero of=/swapfile bs=1G count=2
2+0 records in
2+0 records out
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 2.62 s, 820 MB/s
#创建文件系统
[root@ubuntu2204 ~]# mkswap /swapfile
mkswap: /swapfile: insecure permissions 0644, fix with: chmod 0600 /swapfile
Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=47d86f6d-7670-41ef-8c11-6f6d17cd2588
#查看
[root@ubuntu2204 ~]# blkid /swapfile
/swapfile: UUID="47d86f6d-7670-41ef-8c11-6f6d17cd2588" TYPE="swap"
#修改/etc/fstab,添加行
#创建文件
[root@rocky86 ~]# dd if=/dev/zero of=/swapfile bs=1G count=2
2+0 records in
2+0 records out
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 4.72333 s, 455 MB/s
#创建文件系统
[root@rocky86 ~]# mkswap /swapfile
mkswap: /swapfile: insecure permissions 0644, 0600 suggested.
Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=b1edc27b-2f23-4991-b211-0d2c4bd6a85f
#查看
[root@rocky86 ~]# blkid /swapfile
/swapfile: UUID="b1edc27b-2f23-4991-b211-0d2c4bd6a85f" TYPE="swap"
#修改/etc/fstab,添加行
/swapfile none swap sw 0 0
#启用
[root@ubuntu2204 ~]# swapon /swapfile
swapon: /swapfile: insecure permissions 0644, 0600 suggested.
#查看
[root@ubuntu2204 ~]# swapon -s
Filename Type Size Used Priority
/swap.img file 2097148 0 -2
/dev/sdc3 partition 2097148 3352 123
/swapfile file 2097148 0 -3

永久禁用swap

#删除swap行
[root@ubuntu2204 ~]# sed -i.bak '/swap/d' /etc/fstab
#或注释swap行
[root@ubuntu2204 ~]# sed -i.bak '/swap/s@^@#@' /etc/fstab
#禁用swap,由于修改了配置文件,所以重启也不会有SWAP
[root@ubuntu2204 ~]# swapoff -a

swap的使用策略 

/proc/sys/vm/swappiness 的值决定了当内存占用达到一定的百分比时,会启用swap分区的空间
使用规则

当内存使用率达到100-swappiness时,会启用交换分区
简单地说这个参数定义了系统对swap的使用倾向,此值越大表示越倾向于使用swap
可以设为0,这样做并不会禁止对swap的使用,只是最大限度地降低了使用swap的可能性

范例:

#说明:CentOS7和8默认值为30,内存在使用到100-30=70%的时候,就开始出现有交换分区的使用。
[root@centos8 ~]# cat /proc/sys/vm/swappiness
30
[root@centos7 ~]# cat /proc/sys/vm/swappiness
30
[root@centos6 ~]# cat /proc/sys/vm/swappiness
60
#修改
[root@rocky86 ~]# vim /etc/sysctl.conf
vm.swappiness=0
#生效
[root@rocky86 ~]# sysctl -p
vm.swappiness = 0
[root@ubuntu2204 ~]# cat /proc/sys/vm/swappiness
60


 


 


 


 


 


 


 


 


 


 


 


 


 


 

  • 47
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值