目录
一、正则表达式
REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式;其中有些字符不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能;但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符。
正则表达式被很多程序和开发语言所广泛支持:vim, less,grep,sed,awk, nginx,mysql 等。
正则表达式分两类:
基本正则表达式:BRE Basic Regular Expressions
扩展正则表达式:ERE Extended Regular Expressions
正则表达式引擎:
采用不同算法,检查处理正则表达式的软件模块,如:PCRE(Perl Compatible Regular Expressions)。
正则表达式的元字符分类:
字符匹配、匹配次数、位置锚定、分组帮助:man 7 regex
1.基本正则表达式元字符
①字符匹配
. #匹配任意单个字符(除了\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@ubuntu ~]#grep "a.c" test.txt
abc
abcd
[root@ubuntu ~]#grep "a..d" test.txt
abcd
[root@ubuntu ~]#echo "axxxa" | grep "a...a"
axxxa
[root@ubuntu ~]#echo "x-x" | grep "x.x"
x-x
#范围匹配
[root@ubuntu ~]#ls /etc | grep "rc[.0-9]."
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
#[ ]中匹配的是任意单个字符 [ ]中的.代表它本身 而外面的.代表匹配任意单个字符,\.也代表.本身
[root@ubuntu ~]#ls /etc | grep "rc[0-9]\."
[root@ubuntu ~]#ls /etc | grep "rc[0-9]."
[root@ubuntu ~]#echo 123 | grep '[ab2]'
123
[root@ubuntu ~]#echo 12345 | grep '[^45]'
12345
[root@ubuntu ~]#echo 12a6MMa3bbAA4zz5a%$@ | grep '[0-9]'
[root@ubuntu ~]#echo 12a6MMa3bbAA4zz5a%$@ | grep '[a-z]'
[root@ubuntu ~]#echo 12a6MMa3bbAA4zz5a%$@ | grep '[A-Z]'
[root@ubuntu ~]#echo 12a6MMa3bbAA4zz5a%$@ | grep '[0-Z]'
[root@ubuntu ~]#echo 12a6MMa3bbAA4zz5a%$@ | grep '[^0-9]'
[root@ubuntu ~]#echo 12a6MMa3bbAA4zz5a%$@ | grep '[[:punct:]]'
#匹配空格 - 选定输出后查看
[root@ubuntu ~]#echo "1 2 3 " | grep "[[:blank:]]"
1 2 3
#匹配非空格 - 选定输出后查看
[root@ubuntu ~]#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@ubuntu ~]#echo "rt" | grep "ro*t"
rt
[root@ubuntu ~]#echo "rot" | grep "ro*t"
rot
[root@ubuntu ~]#echo "root" | grep "ro*t"
root
[root@ubuntu ~]#echo "roooooot" | grep "ro*t"
roooooot
#任意长度任意字符
[root@ubuntu ~]#grep "r.*t" /etc/passwd
#0or1次
[root@ubuntu ~]#echo /etc/ | grep "/etc/\?"
/etc/
[root@ubuntu ~]#echo /etc | grep "/etc/\?"
/etc
#>=1
[root@ubuntu ~]#echo google | grep "go\+gle"
google
[root@ubuntu ~]#echo gooooogle | grep "go\+gle"
gooooogle
[root@ubuntu ~]#echo ggle | grep "go\+gle"
#自定义次数
[root@ubuntu ~]#echo google | grep "go\{2\}gle"
google
[root@ubuntu ~]#echo goooooogle | grep "go\{2\}gle"
[root@ubuntu ~]#echo goooooogle | grep "go\{2,10\}gle"
goooooogle
[root@ubuntu ~]#echo goooooogle | grep "go\{,10\}gle"
goooooogle
[root@ubuntu ~]#echo goooooogle | grep "go\{2,\}gle"
goooooogle
#匹配正负数
[root@ubuntu ~]#echo -1 -2 123 -123 234 |grep '-\?[0-9]\+'
grep: invalid option -- '\'
Usage: grep [OPTION]... PATTERNS [FILE]...
Try 'grep --help' for more information.
#grep默认采用基本正则,而模式中规定的是扩展正则
[root@ubuntu ~]#echo -1 -2 123 -123 234 |grep '\-\?[0-9]\+'
-1 -2 123 -123 234
[root@ubuntu ~]#echo -1 -2 123 -123 234 |grep -E '\-?[0-9]+'
-1 -2 123 -123 234
③位置锚定
#位置锚定可以用于定位出现的位置
^ #行首锚定, 用于模式的最左侧
$ #行尾锚定,用于模式的最右侧
^PATTERN$ #用于模式匹配整行
^$ #空行
^[[:space:]]*$ #空白行
\< 或 \b #词首锚定,用于单词模式的左侧
\> 或 \b #词尾锚定,用于单词模式的右侧
\<PATTERN\> #匹配整个单词
#注意: 单词是由字母,数字,下划线组成
#以#开头
[root@ubuntu ~]#grep "^#" /etc/fstab
...
#bash结尾
[root@ubuntu ~]#grep "bash$" /etc/passwd
root:x:0:0:root:/root:/bin/bash
hu:x:1000:1000:hu:/home/hu:/bin/bash
red:x:1001:1001::/home/red:/bin/bash
blue:x:1002:1002::/home/blue:/bin/bash
#所有空行
[root@ubuntu ~]#grep "^$" /etc/fstab
#所有非空行
grep -v "^$" test.txt
#所有非注释行
grep "^[^#]" /etc/fstab
#[^#]表示#以外的任意单个字符,^行首
#排除所有空行和注释行
grep -v "^$" /etc/profile | grep -v "^#" /etc/profile
grep -v -e "^$" /etc/profile -v -e "^#" /etc/profile
grep -v '^$\|^#' /etc/profile
#匹配单词
[root@ubuntu ~]#echo apple blue | grep "\<apple\>"
apple blue
④分组其他
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:(root)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, ... 。\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符。引用的是内容,而不是规则。
注意: \0 表示正则表达式匹配的所有字符。
[root@ubuntu ~]#echo 12333 | grep "123\{3\}"
12333
#(123)作为一个整体出现3次
[root@ubuntu ~]#echo 123123123 | grep "\(123\)\{3\}"
123123123
#后向引用
[root@ubuntu ~]#echo 123123123 | grep "\(123\)\1"
123123123
[root@ubuntu ~]#echo 123123123 | grep "\(123\)\1\1"
123123123
#\1表示引用第一个分组的内容123
[root@ubuntu ~]#echo abc-123/abcabc123 | grep "^\(abc\)-\(123\)/\1\1\2"
abc-123/abcabc123
#或者
a\|b #a或b
C\|cat #C或cat
\(C\|c\)at #Cat或cat
[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
[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
[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
[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
[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
2.扩展正则表达式元字符
①字符匹配
. #任意单个字符
[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
二、文本处理三剑客
1、grep
作用:文本搜索工具,根据用户指定的 “模式” 对目标文本逐行进行匹配检查;打印匹配到的行;模式:由正则表达式字符及文本字符所编写的过滤条件。
基本用法
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@ubuntu ~]#grep hello
123hello123
123hello123
[root@ubuntu ~]#grep -
====---===
====---===
#处理文件
[root@ubuntu ~]#grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
#管道
[root@ubuntu ~]#cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
#标准输入重定向
[root@ubuntu ~]#grep root < /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu ~]#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@ubuntu ~]#grep -v nologin /etc/passwd
...
[root@ubuntu ~]#grep -i RoOt /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu ~]#grep -n bash /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
...
[root@ubuntu ~]#grep -c bash /etc/passwd
4
[root@ubuntu ~]#grep -o root /etc/passwd
root
root
root
[root@ubuntu ~]#grep -q root /etc/passwd
[root@ubuntu ~]#echo $?
0
[root@ubuntu ~]#grep -A 2 root /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@ubuntu ~]#grep -B 2 hu /etc/passwd
sshd:x:113:65534::/run/sshd:/usr/sbin/nologin
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
hu:x:1000:1000:hu:/home/hu:/bin/bash
[root@ubuntu ~]#grep -C 1 hu /etc/passwd
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
hu:x:1000:1000:hu:/home/hu:/bin/bash
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
[root@ubuntu ~]#grep -e root -e hu /etc/passwd
root:x:0:0:root:/root:/bin/bash
hu:x:1000:1000:hu:/home/hu:/bin/bash
[root@ubuntu ~]#grep root /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
[root@ubuntu ~]#grep -f test.txt /etc/passwd
root:x:0:0:root:/root:/bin/bash
#不处理链接
[root@ubuntu ~]# grep -r root /etc/*
#处理链接
[root@ubuntu ~]# grep -R root /etc/*
[root@ubuntu ~]#grep root -l /etc/passwd /etc/shadow /etc/sudoers /etc/fstab
/etc/passwd
/etc/shadow
/etc/sudoers
[root@ubuntu ~]#grep root -L /etc/passwd /etc/shadow /etc/sudoers /etc/fstab
/etc/fstab
[root@ubuntu ~]#grep root -H /etc/passwd /etc/shadow /etc/fstab
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/shadow:root:$y$j9T$SPOIj9sMRRvE8tZy.d5bE.$fmMgZusvsF6IUrKMNaee.xK9gUiTqYZzEH/.Eon.Yt3:20350:0:99999:7:::
#命令行展开
[root@ubuntu ~]#grep `whoami` /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu ~]#echo Linux132 | grep $(uname)
Linux132
#变量展开
[root@ubuntu ~]#grep "$USER" /etc/passwd
root:x:0:0:root:/root:/bin/bash
2、sed
工作原理

Sed行编辑器,是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行。
每当处理一行时,把当前处理的行存储在临时缓冲区模式空间(Pattern Space)中,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。
一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。
如果使用vi命令打开几十M上百M的文件,明显会出现有卡顿的现象,这是因为vi命令打开文件是一次性将文件加载到内存,然后再打开。Sed就避免了这种情况,一行一行的处理,打开速度非常快,执行速度也很快。
帮助:
基本用法
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 #此组合危险,会清空文件
#sed默认会打印所有行到终端-script空,如果使用p则匹配成功的行额外会被打印一次,如果加-i 文件内容会被修改 同样会输出到终端,加-n抑制默认输出 (影响终端输出) 只有使用p 成功匹配替换的行才会打印
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个分组
& #所有搜索内容,引用查找pattern
#等待标准输入,script空,默认直接输出
[root@ubuntu hu]#sed ''
123123123
123123123
[root@ubuntu hu]#sed '' issue
Ubuntu 22.04.5 LTS \n \l
Welcome to Linux - \t
#关闭默认输出,script 为空,则无任何输出
[root@ubuntu hu]#sed -n '' issue
#script中执行p命令,再加上默认输出,所有每行都显示了两次
[root@ubuntu hu]#sed 'p' issue
Ubuntu 22.04.5 LTS \n \l
Ubuntu 22.04.5 LTS \n \l
Welcome to Linux - \t
Welcome to Linux - \t
#用-n 选项关闭默认输出,script 中执行p命令
[root@ubuntu hu]#sed -n 'p' issue
Ubuntu 22.04.5 LTS \n \l
Welcome to Linux - \t
#输出第一行
[root@ubuntu hu]#sed -n '1p' issue
Ubuntu 22.04.5 LTS \n \l
#输出最后一行
[root@ubuntu hu]#sed -n '$p' issue
Welcome to Linux - \t
#范围输出
[root@ubuntu hu]#sed -n '1,2p' issue
Ubuntu 22.04.5 LTS \n \l
Welcome to Linux - \t
#正则匹配,输出包含root的行
[root@ubuntu hu]#sed -n '/root/p' passwd
root:x:0:0:root:/root:/bin/bash
#正则匹配,输出以root开头的行
[root@ubuntu hu]#sed -n '/^root/p' passwd
root:x:0:0:root:/root:/bin/bash
#正则匹配,输出以bash结尾的行
[root@ubuntu hu]#sed -n '/bash$/p' passwd
root:x:0:0:root:/root:/bin/bash
#正则匹配,显示注释行行号
[root@ubuntu hu]#sed -n '/^#/=' fstab
1
2
3
4
5
6
7
8
10
#行号开始,正则结束
[root@ubuntu hu]#sed -n '5,/apple/p' test.txt
5
apple
#添加内容
[root@ubuntu hu]#cat test
aaa
bbb
ccc
ddd
#匹配行后插入
[root@ubuntu hu]#sed '/bbb/a\eee' test
aaa
bbb
eee
ccc
ddd
#指定行前插入
[root@ubuntu hu]#sed '4i\fff' test
aaa
bbb
ccc
fff
ddd
[root@ubuntu hu]#sed '1,3i\---' test
---
aaa
---
bbb
---
ccc
ddd
#替换,第一行替换为ooo
[root@ubuntu hu]#sed '1c\ooo' test
ooo
bbb
ccc
ddd
#替换,第一行替换成两行
[root@ubuntu hu]#sed '1c\ooo\niii' test
ooo
iii
bbb
ccc
ddd
#替换,多行替换成一行
[root@ubuntu hu]#sed '1,2c\333' test
333
ccc
ddd
----------------------------------------------------------------------------------------
[root@ubuntu hu]# seq 10 | sed -n '2,4p'
2
3
4
[root@ubuntu hu]# seq 10 | sed -n '2,+4p'
2
3
4
5
[root@ubuntu hu]# seq 10 | sed -n '8,$p'
8
9
10
[root@ubuntu hu]# seq 10 |sed -n '1~2p'
1
3
5
7
9
[root@ubuntu hu]# seq 10 |sed -n '2~2p'
2
4
6
8
10
#删除奇数行
[root@ubuntu hu]# seq 10 |sed '1~2d'
2
4
6
8
10
#删除偶数行
[root@ubuntu hu]# seq 10 |sed '2~2d'
1
3
5
7
9
#或
[root@ubuntu hu]# #sed -e '2d' -e '4d' seq.log
1
3
5
6
7
8
9
10
#多个script 写在一起
[root@ubuntu hu]# sed '2d;4d' seq.log
1
3
5
6
7
8
9
10
#只显示非#开头的行
[root@ubuntu hu]# sed -n '/^#/!p' /etc/fstab
#不显示注释行和空行
[root@ubuntu hu]# sed '/^$/d;/^#/d' fstab
[root@ubuntu hu]# sed -En '/^(#|$)/!p' fstab
[root@ubuntu hu]# grep -Ev '^#|^$' fstab
#修改文件
#修改前备份
[root@ubuntu hu]# seq 10 > 10.txt
[root@ubuntu hu]# sed -i.bak '2,7d' 10.txt
[root@ubuntu hu]# 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@ubuntu hu] cat 10.txt
1
8
9
10
[root@ubuntu hu] cat 10.txt.bak
1
2
3
4
5
6
7
8
9
10
#不备份
[root@ubuntu hu]# rm -f 10.txt.bak
[root@ubuntu hu]# seq 10 > 10.txt
[root@ubuntu hu]# sed -i '2,7d' 10.txt
[root@ubuntu hu]# ll 10*
-rw-r--r-- 1 root root 9 Jul 23 19:05 10.txt
[root@ubuntu hu]# cat 10.txt
1
8
9
10
#删除注释行和空行
sed -i '/^#/d;/^$/d' fstab
sed -i '/^\(#\|$\)/d' fstab
#搜索替换和&(引用)
sed -n 's/root/ROOT/gp' /etc/passwd
sed -n 's/root/&er/gp' /etc/passwd
sed -n 's/r..t/&er/gp' /etc/passwd
----------------------------------------------------------------------------------------
#除指定文件外其余删除
#取非 1|3|5|7
[root@ubuntu 921]#ls | grep -Ev 'f[1357].txt'
f2.txt
f4.txt
f6.txt
f8.txt
[root@ubuntu 921]#ls | grep -E 'f[^1357].txt'
f2.txt
f4.txt
f6.txt
f8.txt
#删除非1|3|5|7
[root@ubuntu 921]#rm -rf `ls | grep -Ev 'f[1357].txt'`
[root@ubuntu 921]#ls
f1.txt f3.txt f5.txt f7.txt
#取非 1|3|5|7
[root@ubuntu 921]#ls | sed -n '/f[^1357].txt/p'
f2.txt
f4.txt
f6.txt
f8.txt
#删除非1|3|5|7
[root@ubuntu 921]#rm -rf `ls | sed -n '/f[^1357].txt/p'`
[root@ubuntu 921]#ls
f1.txt f3.txt f5.txt f7.txt
[root@ubuntu 921]#ls | grep -Ev 'f[1357]\.txt' | sed -n 's/.*/rm &/p'
rm f2.txt
rm f4.txt
rm f6.txt
rm f8.txt
[root@ubuntu 921]#ls | grep -Ev 'f[1357]\.txt' | sed -n 's/.*/rm &/p' | bash
[root@ubuntu 921]#ls
f1.txt f3.txt f5.txt f7.txt
[root@ubuntu 921]# ls | grep -Ev 'f-(1|3|5|7)\.txt' | sed -En 's/(.*)/rm \1/p' | bash
#命令展开
[root@ubuntu hu]#sed -n "/$(whoami)/p" passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu hu]#sed -n "$[$(id -u)+1]p" passwd
root:x:0:0:root:/root:/bin/bash
#$[]算术运算符 $()命令展开
[root@ubuntu hu]#sed -n "$(echo `cat /etc/passwd | wc -l`)p" passwd
m2:x:1002:1002::/home/m2:/bin/sh
#变量和命令
[root@ubuntu hu]#sed -n "$(echo ${UID}+1|bc)p" passwd
root:x:0:0:root:/root:/bin/bash
[root@ubuntu hu]#sed -n "$(echo ${UID}+1|bc),$(echo ${UID}+3|bc)p" 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
高级用法(了解)
sed 中除了模式空间,还另外还支持保持空间(Hold Space),利用此空间,可以将模式空间中的数据,临时保存至保持空间,从而后续接着处理,实现更为强大的功能。

#高级命令
P #打印模式空间开端至\n内容,并追加到默认输出之前
h #把模式空间中的内容覆盖至保持空间中
H #把模式空间中的内容追加至保持空间中
g #从保持空间取出数据覆盖至模式空间
G #从保持空间取出内容追加至模式空间
x #把模式空间中的内容与保持空间中的内容进行互换
n #读取匹配到的行的下一行覆盖至模式空间
N #读取匹配到的行的下一行追加至模式空间
d #删除模式空间中的行
D #如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循环
3、awk
工作原理和基本用法说明
awk 是一种强大的 文本处理工具 和 编程语言,报告生成器,格式化文本输出,擅长对结构化文本数据(如日志、CSV、表格等)进行 按列处理、计算、格式化输出。它逐行读取输入,并根据指定的规则处理数据。
awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…
#常用选项
-f progfile|--file progfile #从文件中读入program
-F fs|--field-separator fs #指定分隔符,默认是空白符,可以指定多个
-v var=val|--asign var=val #设置变量
program用法
#program 通常放在单引号中,由三部份组成,分别是BEGIN{}[pattern]{COMMAND}END{},这三部份可以没有或都有
awk '' /etc/issue
awk 'BEGIN{print "begin"}' /etc/issue
awk '{print $0}' /etc/issue
awk 'END{print "end"}' /etc/issue
awk 'BEGIN{print "begin"}{print $0}END{print "end"}' /etc/issue
program格式
pattern{action statements;..}
pattern #定义条件,只有符合条件的记录,才会执行后面的action
action statements #处理数据的方式,常见如 print,printf等
awk工作过程

1. 执行BEGIN{ action;... }语句块中的语句。
2. 从文件或标准输入(stdin)读取一行,然后执行pattern{ action;...}语句块,它逐行扫描文件,从 第一行到最后一行重复这个过程,直到文件全部被读取完毕。
3. 当读至输入流末尾时,执行END{ action;...}语句块。说明:
⚪BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
⚪END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。⚪pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
分割符、域和记录
⚪文件的每一行称为记录 record。
⚪记录可以由指定的分隔符分隔成多个字段(列 column,域 field),由$1,$2...$N 来标识每一个字段,$0 表示一整行。
awk变量
内置变量

#FILENAME
#begin中拿不到FILENAME,执行先于读取文件处理
[root@rocky-151 105]#awk 'BEGIN{print FILENAME}' /etc/passwd
[root@rocky-151 105]#
[root@rocky-151 105]#awk 'BEGIN{print FILENAME}{print "test"}END{print FILENAME}' /etc/passwd
test
test
...
/etc/passwd
#FS
[root@ubuntu2204 ~]# awk -v FS=":" 'BEGIN{print FS}{print $1,$1}' /etc/passwd
:
root root
daemon daemon
...
[root@ubuntu2204 ~]# awk -v FS=":" 'BEGIN{print FS}{print $1FS$1}' /etc/passwd
:
root:root
daemon:daemon
..
#使用-F选项指定
[root@ubuntu2204 ~]# awk -F: 'BEGIN{print FS}{print $1FS$1}' /etc/passwd
:
root:root
daemon:daemon
...
#从shell变量中获取
[root@ubuntu2204 ~]# str=":";awk -v FS=$str 'BEGIN{print FS}{print $1FS$1}'
/etc/passwd
:
root:root
daemon:daemon
...
#-F和FS变量功能一样,同时使用后面会覆盖前面的
[root@ubuntu2204 ~]# awk -v FS=":" -F";" 'BEGIN{print FS}' /etc/passwd
;
[root@ubuntu2204 ~]# awk -F";" -v FS=":" 'BEGIN{print FS}' /etc/passwd
#例子
[root@ubuntu2204 ~]# df -h | awk '{print $5}' | tr -d "%" | sort -nr | head -1
14
[root@ubuntu2204 ~]# df -h | awk -F" +|%" '{print $5}' | sort -nr | head -1
14
#RS
[root@rocky-151 105]#cat -A test.txt
a b c;1 2 3;x y z$
[root@rocky-151 105]#awk '{print $0}' test.txt
a b c;1 2 3;x y z
[root@rocky-151 105]#awk -v RS=";" '{print $0}' test.txt
a b c
1 2 3
x y z
#原本这里的$还在 因此输出两行但其实是一行
[root@rocky-151 105]#
#OFS
[root@rocky-151 105]#awk -v FS=":" '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
...
[root@rocky-151 105]#awk -v FS=":" -v OFS="---" '{print $1,$3}' /etc/passwd
root---0
bin---1
daemon---2
...
#ORS
[root@rocky-151 105]#cat -A test.txt
123$
456$
789$
[root@rocky-151 105]#awk '{print $0}' test.txt
123
456
789
[root@rocky-151 105]#awk -v ORS="---" '{print $0}' test.txt
123---456---789---[root@rocky-151 105]#
#OFMT
[root@rocky-151 105]#awk 'BEGIN{PI=3.1415926;print PI;OFMT="%.1g";print PI;OFMT="%.2g";print PI;OFMT="%.8g";print PI;OFMT="%.8f";print PI}'
3.14159
3
3.1
3.1415926
3.14159260
#NF
[root@ubuntu2204 ~]# awk -v FS=":" '{print NF}' /etc/passwd
7
7
7
... #有多少条记录就输出多少
[root@ubuntu2204 ~]# awk -v FS=":" '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
[root@ubuntu2204 ~]# awk -v FS=":" '{print $(NF-1)}' /etc/passwd
/root
/bin
/sbin
#NR
[root@rocky-151 105]#awk '{print NR,$0}' /etc/issue
1 \S
2 Kernel \r on an \m
3 ---Welcome to Linux!---
#FNR
[root@rocky-151 105]#awk '{print NR,FNR,$0}' /etc/issue /etc/fstab
1 1 \S
2 2 Kernel \r on an \m
3 3 ---Welcome to Linux!---
4 1
5 2 #
6 3 # /etc/fstab
7 4 # Created by anaconda on Thu Sep 18 06:10:23 2025
8 5 #
9 6 # Accessible filesystems, by reference, are maintained under '/dev/disk/'.
10 7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
11 8 #
12 9 # After editing this file, run 'systemctl daemon-reload' to update systemd
13 10 # units generated from this file.
14 11 #
15 12 /dev/mapper/rl-root / xfs defaults 0 0
16 13 UUID=202a26bd-1f18-4fae-bdf8-c1096dafbadd /boot xfs defaults 0 0
17 14 UUID=24A0-CF4F /boot/efi vfat umask=0077,shortname=winnt 0 2
18 15 /dev/mapper/rl-home /home xfs defaults 0 0
19 16 /dev/mapper/rl-swap none swap defaults 0 0
20 17
21 18
#ARGC-awk 程序本身和输入文件
[root@ubuntu2204 ~]# awk 'BEGIN{print ARGC}'
1
[root@ubuntu2204 ~]# awk 'BEGIN{print ARGC}' /etc/issue
2
[root@ubuntu2204 ~]# awk 'BEGIN{print ARGC}' /etc/issue /etc/os-relaease
3
#ARGV
[root@rocky-151 105]#awk 'BEGIN{print ARGC,"---",ARGV[0],"---",ARGV[1],"---",ARGV[2],"---",ARGV[3]}' /etc/issue /etc/fstab /etc/passwd
4 --- awk --- /etc/issue --- /etc/fstab --- /etc/passwd
自定义变量
#AWK中的自定义变量命名要区分大小写
#用 -v 选项定义自定义变量
[root@rocky-151 105]#awk -v var1=abc 'BEGIN{print var1}'
abc
[root@rocky-151 105]#awk -v var1=abc -v var1=xyz 'BEGIN{print var1}'
xyz
#在program中定义
[root@rocky-151 105]#awk -v var1=abc 'BEGIN{print var1;var1=ufo;print var1}'
abc
#将ufo作为变量传给var1 但是ufo空值,定于的时候需要加双引号
[root@rocky-151 105]#awk -v var1=abc 'BEGIN{print var1;var1="ufo";print var1}'
abc
ufo
动作print
print item1,item2, ...说明:
⚪逗号分隔符。
⚪输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式。
⚪如省略item,相当于print $0 。
⚪固定字符串需要用 " " 引起来,而变量和数字不需要。
[root@rocky-151 105]#awk 'BEGIN{print "hello world"}'
hello world
[root@rocky-151 105]#awk 'BEGIN{print "hello world"}' /etc/issue
hello world
[root@rocky-151 105]#awk '{print "hello world"}' /etc/issue
hello world
hello world
hello world
[root@rocky-151 105]#seq 3 | awk '{print "hello world"}'
hello world
hello world
hello world
[root@rocky-151 105]#seq 3 | awk '{print $0}'
1
2
3
[root@rocky-151 105]#awk 'BEGIN{print 5*5}'
25
[root@rocky-151 105]#awk -v var1=555 -F: '{print var1,$1,$3}' /etc/passwd
555 root 0
555 bin 1
555 daemon 2
...
[root@rocky-151 105]#awk -v var1=555 -F: '{print var1,$1"\t"$3}' /etc/passwd
555 root 0
555 bin 1
555 daemon 2
...
动作printf
#printf 可以实现格式化输出 printf "FORMAT",item1,item2,... #格式符-与item一一对应 %s #显示字符串 %d|%i #显示十进制整数 %f #显示为浮点数 %e|%E #显示科学计数法数值 %c #显示字符的ASCII码 %g|%G #以科学计数法或浮点形式显示数值 %u #无符号整数 %% #显示%自身 #修饰符 M[.N] #M表示显示的宽度;N表示小数点后精度,如%3.1f - #左对齐(默认右对齐) 如 %-15s + #显示数值的正负符号 如 %+d说明:
⚪必须指定FORMAT 。
⚪不会自动换行,需要显式给出换行控制符 \n 。
⚪FORMAT中需要分别为后面每个item指定格式符。
[root@rocky-151 105]#awk -F: '{printf "%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodytsssystemd-coredumpdbuspolkitdsssdavahigeocluertkitpipewirelibstoragemgmtcockpit-wsinstanceflatpakcolordclevissetroubleshootgdmgnome-initial-setupchronysshddnsmasqtcpdumpxiaohucatnginxpostfix[root@rocky-151 105]#awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
daemon
...
[root@rocky-151 105]#awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
root 0
bin 1
daemon 2
...
[root@rocky-151 105]#awk -F: '{printf "username: %s\n",$1}' /etc/passwd
username: root
username: bin
username: daemon
...
[root@rocky-151 105]#awk -F: '{printf "username: %20s uid: %15s\n",$1,$3}' /etc/passwd
username: root uid: 0
username: bin uid: 1
username: daemon uid: 2
...
[root@rocky-151 105]#awk -F: '{printf "username: %-20s uid: %15s\n",$1,$3}' /etc/passwd
username: root uid: 0
username: bin uid: 1
username: daemon uid: 2
...
awk -F: 'BEGIN{print "---------------------------\n|username |uid |\n---------------------------"}{printf "|%-20s|%5s|\n---------------------------\n",$1,$3}' /etc/passwd
操作符
赋值操作
=, +=, -=, *=, /=, %=, ^=, ++, --比较操作
==, !=, >, >=, <, <=算术运算符
x+y, x-y, x*y, x/y, x^y, x%y -x #转换为负数 +x #将字符串转换为数值模式匹配操作
~ #左边是否和右边匹配,包含关系 !~ #是否不匹配逻辑操作符
&& #与,并且关系 || #或,或者关系 ! #非,取反三目运算
selector?if-true-expression:if-false-expression
[root@ubuntu2204 ~]# awk 'BEGIN{i=0;print i++,i}'
0 1
[root@ubuntu2204 ~]# awk 'BEGIN{i=0;print ++i,i}'
1 1
[root@ubuntu2204 ~]# awk 'BEGIN{i=0;print ++i,++i}'
1 2
[root@ubuntu2204 ~]# awk 'BEGIN{i=0;print ++i,i++}'
1 1
[root@rocky-151 105]#seq 3 | awk 'n++'
2
3
#完整写法awk 'n++{print $0}' 此处n变量没有复制则0 当处理seq 1时候 为假则不输出1 后续n++保证真则可输出
[root@rocky-151 105]#awk -v n=0 '!n++' /etc/passwd
root:x:0:0:root:/root:/bin/bash
#此处!表示取反第一次n=0取反真则执行 后续n++ n=1取反为假不执行
[root@ubuntu2204 ~]# awk -v n=0 '!n++{print n}' /etc/passwd
1
[root@rocky-151 105]#awk -v n=0 '!n++{print n}' /etc/passwd
1
[root@rocky-151 105]#awk -v n=1 '!n++{print n}' /etc/passwd
[root@rocky-151 105]#awk -v n=-1 '!n++{print n}' /etc/passwd
1
[root@rocky-151 105]#awk 'NR==2' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
[root@rocky-151 105]#awk -F: '$3>=1000' /etc/passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
xiaohu:x:1000:1000:xiaohu:/home/xiaohu:/bin/bash
cat:x:1001:1001::/home/cat:/bin/bash
#取奇数偶数行
[root@rocky-151 105]#seq 6 | awk '$NF%2==0'
2
4
6
[root@rocky-151 105]#seq 6 | awk '$NF%2==1'
1
3
5
#包含root的行
[root@rocky-151 105]#awk -F: '$0 ~ /root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@rocky-151 105]#awk -F: '$0 ~ "root"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@rocky-151 105]#awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
#root开头的行
[root@rocky-151 105]#awk -F: '$0 ~ /^root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@rocky-151 105]#awk -F: '$0 ~ "^root"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@rocky-151 105]#awk -F: '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
#不包含root的行
[root@rocky-151 105]#awk -F: '$0 !~ /root/{print $0}' /etc/passwd
#uid=0的行
[root@rocky-151 105]#awk -F: '$3==0' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@rocky-151 105]#awk -F: '$3>1000' /etc/passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
cat:x:1001:1001::/home/cat:/bin/bash
[root@rocky-151 105]#df -h | awk -F"[[:space:]]+" '$0 ~ "^/dev/sda"{print $5}' | sort -nr | head -1
36%
[root@rocky-151 105]#ifconfig ens160 | awk 'NR==2{print $2}'
10.0.0.151
[root@ubuntu2204 ~]# awk 'BEGIN{print i}'
[root@ubuntu2204 ~]# awk 'BEGIN{print !i}'
1
[root@ubuntu2204 ~]# awk -v i=10 'BEGIN{print !i}'
0
[root@ubuntu2204 ~]# awk -v i=0 'BEGIN{print !i}'
1
[root@ubuntu2204 ~]# awk -v i=-10 'BEGIN{print !i}'
0
[root@ubuntu2204 ~]#awk -v i=abc 'BEGIN{print !i}'
0
[root@ubuntu2204 ~]# awk -v i='' 'BEGIN{print !i}'
1
[root@rocky-151 105]#awk -v i= 'BEGIN{print i}'
[root@rocky-151 105]#awk -v i= 'BEGIN{print !i}'
1
[root@rocky-151 105]#awk -v i=0 'BEGIN{print i}'
0
[root@rocky-151 105]#awk -v i=0 'BEGIN{print !i}'
1
[root@rocky-151 105]#awk -v i="" 'BEGIN{print i}'
[root@rocky-151 105]#awk -v i="" 'BEGIN{print !i}'
1
[root@rocky-151 105]#awk -v i=" " 'BEGIN{print i}'
[root@rocky-151 105]#awk -v i=" " 'BEGIN{print !i}'
0
[root@rocky-151 105]#awk -v i="0" 'BEGIN{print i}'
0
[root@rocky-151 105]#awk -v i="0" 'BEGIN{print !i}'
1
[root@rocky-151 105]#
[root@rocky-151 105]#awk -F: '$3>=0 && $3<5{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
[root@rocky-151 105]#awk -F: '$3<1 || $3>1000{print $1,$3}' /etc/passwd
root 0
nobody 65534
cat 1001
[root@rocky-151 105]#awk -F: '!($3!=0) {print $1,$3}' /etc/passwd
root 0
[root@rocky-151 105]#awk -F: '{$3>=1000?utype="comm":utype="sys";printf "%-20s:%8s\n",$1,utype}' /etc/passwd
root : sys
bin : sys
daemon : sys
...
[root@rocky-151 105]#df|awk -F"[ % | awk -F"[ %]+" '/^\/dev\/sd/{$(NF-1)>10?disk="full":disk="okF-1),disk}'
36 full
2 ok
[root@rocky-151 105]#cat scores.txt
aaa 100
bbb 90
ccc 50
ddd 60
eee 70
[root@rocky-151 105]#awk '$2>=60?type="pass":type="nopass"{print $1,type}' scores.txt
aaa pass
bbb pass
ccc nopass
ddd pass
eee pass
模式PATTERN
PATTERN:根据pattern条件,过滤匹配的行,再做处理,如果没有指定,则匹配每一行。
正则匹配
#用正则匹配,正则表达式需要用/ / 来锚定开始结束
root@rocky-151 105]#awk '/^UUID/{print $1}' /etc/fstab
UUID=202a26bd-1f18-4fae-bdf8-c1096dafbadd
UUID=24A0-CF4F
#非空行非注释行
[root@rocky-151 105]#awk '!/^$|^#/{print $1}' /etc/fstab
/dev/mapper/rl-root
UUID=202a26bd-1f18-4fae-bdf8-c1096dafbadd
UUID=24A0-CF4F
/dev/mapper/rl-home
/dev/mapper/rl-swap
[root@rocky-151 105]#awk '!/^($|#)/{print $1}' /etc/fstab
/dev/mapper/rl-root
UUID=202a26bd-1f18-4fae-bdf8-c1096dafbadd
UUID=24A0-CF4F
/dev/mapper/rl-home
/dev/mapper/rl-swap
关系表达式
关系表达式,结果为“真”才会被处理。真:结果为非0值,非空字符串,假:结果为0值或空字符串。
[root@ubuntu2204 ~]# seq 3 | awk '1'
1
2
[root@ubuntu2204 ~]# seq 3 | awk '!1'
[root@ubuntu2204 ~]# seq 3 | awk '0'
[root@ubuntu2204 ~]# seq 3 | awk '!0'
1
2
3
#false 这里表示的是一个未定义的变量,不是表示bool值
[root@ubuntu2204 ~]# seq 3 | awk 'false'
[root@ubuntu2204 ~]# seq 3 | awk -v false=123 'false'
1
2
3
#false 这里表示的是字符串
[root@ubuntu2204 ~]# seq 3 | awk '"false"'
1
2
3
[root@ubuntu2204 ~]# seq 3 | awk '""'
[root@ubuntu2204 ~]# seq 3 | awk '" "'
1
2
3
[root@ubuntu2204 ~]# seq 3 | awk '"0"'
1
2
3
[root@ubuntu2204 ~]# seq 3 | awk '0'
#这里true 是变量名,一个不存在的变量
[root@ubuntu2204 ~]# seq 3 | awk 'true'
[root@ubuntu2204 ~]# seq 3 | awk -v true=123 'true'
1
2
3
[root@ubuntu2204 ~]# seq 3 | awk '123'
1
2
3
[root@ubuntu2204 ~]# seq 3 | awk 'hu'
[root@ubuntu2204 ~]# seq 3 | awk -v hu="hu" 'hu'
1
2
3
[root@ubuntu2204 ~]# seq 3 | awk -v hu="" 'hu'
[root@ubuntu2204 ~]# seq 3 | awk -v hu=" " 'hu'
1
2
3
[root@ubuntu2204 ~]# seq 3 | awk -v hu=0 'hu'
[root@ubuntu2204 ~]# seq 3 | awk 'i'
#赋值
[root@ubuntu2204 ~]# seq 3 | awk 'i=0'
#比较
[root@ubuntu2204 ~]# seq 3 | awk 'i==0'
1
2
3
#赋值
[root@ubuntu2204 ~]# seq 3 | awk 'i=1'
1
2
3
#比较
[root@ubuntu2204 ~]#seq 3 | awk 'i==1'
#比较
[root@ubuntu2204 ~]# seq 3 | awk 'i==i'
1
2
3
#比较
[root@ubuntu2204 ~]# seq 3 | awk 'i!=i'
#赋值 i=false
[root@ubuntu2204 ~]# seq 3 | awk 'i=i'
#赋值 tru false true
[root@ubuntu2204 ~]# seq 3 | awk 'i=!i'
1
3
[root@ubuntu2204 ~]# seq 4 | awk '{i=!i;print i}'
1
0
1
0
[root@ubuntu2204 ~]# seq 8 | awk '!(i=!i)'
2
4
#赋值 i=false
[root@ubuntu2204 ~]# seq 3 | awk 'i=i'
#赋值 tru false true
[root@ubuntu2204 ~]# seq 3 | awk 'i=!i'
1
3
[root@ubuntu2204 ~]# seq 4 | awk '{i=!i;print i}'
1
0
1
0
[root@ubuntu2204 ~]# seq 8 | awk '!(i=!i)'
2
4
6
8
[root@ubuntu2204 ~]# seq 8 | awk -v i=1 'i=!i'
2
4
6
8
[root@ubuntu2204 ~]# cat test.txt
1111111
2222222
aaaaaaa
bbbbbbb
[root@ubuntu2204 ~]# awk 'i=1;j=1{print i,j}' test.txt
1111111
1 1
2222222
1 1
aaaaaaa
1 1
bbbbbbb
1 1
#[root@ubuntu2204 ~]# awk 'i=1{print $0};j=1{print i,j}' test.txt
[root@ubuntu2204 ~]# awk 'i=1,j=1{print i,j}' test.txt
1 1
1 1
1 1
1 1
行范围
不支持直接用行号,但可以使用变量NR间接指定行号,也可以用正则锚定开始结束行。
[root@ubuntu2204 ~]# seq 10 | awk 'NR>=3 && NR<6'
3
4
5
[root@ubuntu2204 ~]# awk 'NR>=3 && NR<6{print NR,$0}' /etc/passwd
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 sync:x:4:65534:sync:/bin:/bin/sync
#sed 写法
[root@ubuntu2204 ~]# sed -n '3,5p' /etc/passwd
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
#正则锚定
[root@rocky-151 105]#awk '/^bin/,/^adm/' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
#sed写法
[root@rocky-151 105]#sed -n '/^bin/,/^adm/p' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次。
END{}:仅在文本处理完成之后执行一次。
#只有begin 时,可以没有输入内容
[root@rocky-151 105]#awk 'BEGIN{print "begin"}'
begin
#需要后续输入
[root@rocky-151 105]#awk 'BEGIN{print "begin"}{}'
begin
^C
[root@rocky-151 105]#
[root@rocky-151 105]#awk 'BEGIN{print "begin"}{print $0}END{print "end"}' /etc/issue
begin
\S
Kernel \r on an \m
---Welcome to Linux!---
end
条件判断if-else
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3)
{statement3}...... else {statementN}
[root@rocky-151 105]#awk -F: '{if($3>1000)print $1,$3}' /etc/passwd
nobody 65534
cat 100
[root@rocky-151 105]#awk -F: '{if($3<=100){print "<=100",$1,$3}else if($3<=1000){print "<=1000",$1,$3}else print ">1000",$1,$3}' /etc/passwd
<=100 root 0
<=100 bin 1
<=100 daemon 2
...
[root@rocky-151 105]#awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
root
xiaohu
cat
[root@rocky-151 105]#awk -F: '{if(NF>5)print $0}' /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
...
[root@rocky-151 105]#awk -F: '{if($3>1000){printf "comm user:%s\n",$1}else {printf "sys user:%s\n",$1}}' /etc/passwd
sys user:root
sys user:bin
sys user:daemon
...
[root@rocky-151 105]#df -h | awk -F% '/^\/dev\/sda2/{print $1}'| awk '$NF>=10{print $1,$5}'
/dev/sda2 36
[root@rocky-151 105]#df | awk -F"[[:space:]]+|%" '/^\/dev\/sd/{if($5>10)print $1,$5}'
/dev/sda2 36
[root@rocky-151 105]#awk 'BEGIN{ test=100;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
very good
条件判断switch-case
awk 中的switch分支语句功能较弱,只能进行等值比较或正则匹配,各分支结尾需使用break来终止。
switch(expression) {
case VALUE1 or /REGEXP1/:
statement1;
break;
case VALUE2 or /REGEXP2/:
statement2;
break;
......;
default:
statementn;
break;
}
#分支穿透
switch(expression) {
case VALUE1 or /REGEXP1/:
case VALUE2 or /REGEXP2/:
case VALUE3 or /REGEXP3/:
statement1;
break;
case VALUE4 or /REGEXP4/:
statement2;
break;
......;
default:
statementn;
break;
}
[root@rocky-151 105]#awk -F: '{switch($3){case 0:print "root",$3;break;case /^[1-9][0-9]{0,2}$/:print "sys user",$3;break;default:print "comm user",$3}}' /etc/passwd
root 0
sys user 1
sys user 2
sys user 3
sys user 4
sys user 5
sys user 6
sys user 7
sys user 8
sys user 11
sys user 12
sys user 14
comm user 65534
sys user 59
循环while
条件“真”,进入循环;条件“假”,退出循环。
使用场景: 对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用。
while (condition) {statement;…}
[root@rocky-151 105]#awk -v i=1 -v sum=0 'BEGIN{while(i<=100){sum+=i;i++};print sum}'
5050
[root@rocky-151 105]#awk 'BEGIN{total=0;i=1;while(i<=100){total+=i;i++};print total}'
5050
循环do-while
无论真假,至少执行一次循环体。
do {statement;…}while(condition)
[root@rocky-151 105]#awk 'BEGIN{total=0;i=101;do{print total}while(i<=100);}'
0
[root@rocky-151 105]#awk 'BEGIN{total=0;i=1;do{total+=i;i++;}while(i<=100);print total}'
5050
循环for
for(expr1;expr2;expr3) {statement;…}
#特殊用法:能够遍历数组中的元素
for(var in array) {for-body}
[root@rocky-151 105]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
5050
#shell实现
[root@rocky-151 105]#for((i=0,sum=0;i<=100;i++));do let sum+=i;done;echo $sum
5050
#遍历数组
[root@rocky-151 105]#awk 'BEGIN{arr[0]=123;arr[1]=456;arr[2]=789;for(i in arr){print i"-->"arr[i]}}'
0-->123
1-->456
2-->789
#面试题:文件中只有一串数字计算求和?
[root@rocky-151 105]#cat a.txt
1 2 3 4 5
[root@rocky-151 105]#cat a.txt | awk '{for(i=1;i<=NF;i++){sum+=$i};print sum}'
15
[root@rocky-151 105]#cat a.txt | tr ' ' + | bc
15
[root@rocky-151 105]#sum=0;for i in `cat a.txt`;do let sum+=i;done;echo $sum
15
#随机取字符串中的数字
[root@ubuntu-158 ~]#echo "1Ees%$@42L1W" | awk -F "" '{for(i=1;i<=NF;i++){if($i ~ /[0-9]/){str=(str $i)}}print str}'
1421
continue和break
continue 中断本次循环,break 中断整个循环。
continue [n]
break [n]
[root@ubuntu-158 ~]#awk 'BEGIN{for(i=1;i<=100;i++)sum+=i;print sum}'
5050
[root@ubuntu-158 ~]#awk 'BEGIN{for(i=1;i<=100;i++){if(i==50)continue;sum+=i;}print sum}'
5000
[root@ubuntu-158 ~]#awk 'BEGIN{for(i=1;i<=100;i++){if(i==50)break;sum+=i;}print sum}'
1225
[root@ubuntu-158 ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i;}print sum}'
1225
[root@ubuntu-158 ~]#awk 'BEGIN{sum=0;for(i=1;i<50;i++)sum+=i;print sum}'
1225
next
next 可以提前结束对本行处理而直接进入下一行处理(awk自身循环)。
[root@ubuntu-158 ~]#seq 10 | awk '{if($0%2!=0){next;}print $0}'
2
4
6
8
10
数组
#awk的数组为关联数组
array_name[index-expression]
#说明
利用数组,实现 k/v 功能
可使用任意字符串;字符串要使用双引号括起来
如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
[root@ubuntu-158 ~]#awk 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";weekdays["wed"]="wedsnesday";print weekdays["wed"]}'
wedsnesday
[root@ubuntu-158 ~]#awk 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";weekday["wed"]="wedsnesday";print weekdays["mon"]}'
monday
#判断数组索引是否存在
[root@ubuntu-158 ~]#awk 'BEGIN{arr["i"]="x";arr["j"]="y";if("i" in arr){print "yes"}else{print "no"}}'
yes
[root@ubuntu-158 ~]#awk 'BEGIN{arr["i"]="x";arr["j"]="y";if("z" in arr){print "yes"}else{print "no"}}'
no
[root@ubuntu-158 ~]#awk 'BEGIN{arr["i"]="x";arr["j"]="y";print "i" in arr,"z" in arr}'
1 0
若要遍历数组中的每个元素,要使用 for 循环。
for(var in array) {for-body} #var为数组下标索引,不是数组的值
[root@ubuntu-158 ~]#awk 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";weekdays["wed"]="wedsnesday";for(i in weekdays){print i"---"weekdays[i]}}'
wed---wedsnesday
tue---tuesday
mon---monday
#i表示数组下标索引,而非数组的值
[root@ubuntu-158 ~]#awk -F: '{user[$1]=$3};END{for(i in user){print "username:"i"---""uid:"user[i]}}' /etc/passwd
username:hu---uid:1000
username:sshd---uid:108
username:tcpdump---uid:105
username:usbmux---uid:101
[root@ubuntu2204 ~]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}'
/var/log/httpd/access_log
172.20.0.200 1482
..
[root@ubuntu2204 ~]# awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' access_log
|sort -nr| head -3
4870 172.20.116.228
...
[root@ubuntu2204 ~]# wk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log |sort -k2 -nr|head -3
172.20.116.228 4870
172.20.116.208 3429
172.20.0.222 2834
#封掉查看访问日志中连接次数超过1000次的IP
[root@ubuntu2204 ~]# awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){system("iptables -A INPUT -s "i" -j REJECT")}}}' nginx.access.log-20200428
#多维数组
[root@ubuntu-158 ~]#awk 'BEGIN{arr[1][1]=11;arr[1][2]=12;arr[2][1]=21;arr[2][2]=22;for(i in arr){for (j in arr[i])print arr[i][j]}}'
11
12
21
22
[root@ubuntu-158 ~]#cat avg.txt
name sex score
xiaohu m 100
xiaowang f 90
xiaohong f 95
xiaoliu m 90
[root@ubuntu-158 ~]#awk 'NR!=1{if($2=="m"){m_sum+=$3;m_num++}else{f_sum+=$3;f_num++}}END{print "男生平均成绩:"m_sum/m_num,"女生平均成绩:"f_sum/f_num}' avg.txt
男生平均成绩:95 女生平均成绩:92.5
[root@ubuntu-158 ~]#awk 'NR!=1{score[$2]+=$3;num[$2]++}END{for (i in score){print i,score[i]/num[i]}}' avg.txt
m 95
f 92.5
[root@ubuntu-158 ~]#awk 'NR!=1{score[$2]+=$3;num[$2]++}END{for (i in score){if(i=="m"){print i,score[i]/num[i]}else{print i,score[i]/num[i]}}}' avg.txt
m 95
f 92.5
awk函数
帮助:https://www.gnu.org/software/gawk/manual/gawk.html#Functions
内置函数
数值处理
rand() #返回0和1之间一个随机数
srand() #配合rand() 函数,生成随机数的种子
int() #返回整数
[root@ubuntu-158 ~]#awk 'BEGIN{print rand()}'
0.924046
[root@ubuntu-158 ~]#awk 'BEGIN{srand();print rand()}'
0.927273
[root@ubuntu-158 ~]#awk 'BEGIN{srand();print rand()}'
0.291634
[root@ubuntu-158 ~]#awk 'BEGIN{srand();print int(rand()*10)}'
7
[root@ubuntu-158 ~]#awk 'BEGIN{srand();print int(rand()*10)}'
2
字符串处理
str1=(str2,str3) #连字符,字符串拼接
length([s]) #返回字符串 s 的长度(若省略 s,则返回 $0 的长度)
sub(r,s,[t]) #在t中串搜索r匹配的内容,并将第一个匹配内容替换为s
gsub(r,s,[t]) #在t中串搜索r匹配的内容,并将匹配内容全部替换为s,即贪婪模式
split(s,array,[r]) # 以分隔符 r(默认 FS)切割字符串 s,结果存入数组 array(索引从 1 开始)
[root@ubuntu-158 ~]#awk 'BEGIN{str2="hello";str3="world";print str1=(str2 str3)}'
helloworld
[root@ubuntu-158 ~]#awk 'BEGIN{str="123asdzxc@%$1!";print length(str)}'
14
[root@ubuntu-158 ~]#awk 'BEGIN { s = "banana"; sub(/a/, "A", s); print s }'
bAnana
[root@ubuntu-158 ~]#awk 'BEGIN { s = "banana"; gsub(/a/, "A", s); print s }'
bAnAnA
#[t]省略时,此时默认操作的字符串是$0
[root@ubuntu-158 ~]#echo "apple banana apple" | awk '{sub(/apple/, "orange");print }'
orange banana apple
[root@ubuntu-158 ~]#echo "apple banana apple" | awk '{gsub(/apple/, "orange");print }'
orange banana orange
[root@ubuntu-158 ~]#awk 'BEGIN{s="x:y:z";split(s,arr,":");for(i in arr)print i,arr[i]}'
1 x
2 y
3 z
#统计用户名的长度
[root@ubuntu-158 ~]#cut -d: -f1 /etc/passwd | awk '{print length()}'
4
6
3
[root@ubuntu-158 ~]#awk -F: '{print length($1)}' /etc/passwd
4
6
3
[root@ubuntu2204 ~]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
2008-08:08 08:08:08
[root@ubuntu2204 ~]# echo "2008:08:08 08:08:08" | awk '{sub(/:/,"-",$1);print $0}'
2008-08:08 08:08:08
[root@ubuntu2204 ~]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
2008-08-08 08-08-08
[root@ubuntu2204 ~]# echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$0);print
$0}'
2008-08-08 08-08-08
[root@ubuntu2204 ~]# netstat -tn | awk '/^tcp/{split($4,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
10.0.0.1 1
...
调用shell命令
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用""引用起来。
system('cmd')
[root@ubuntu-158 ~]#awk 'BEGIN{system("hostname")}'
ubuntu-158
时间函数
systime() #当前时间到1970年1月1日的秒数
strftime() #指定时间格式
[root@ubuntu-158 ~]#awk 'BEGIN{print systime()}'
1759735977
[root@ubuntu-158 ~]#awk 'BEGIN{print systime();system("date +%s")}'
1759735996
1759735996
[root@ubuntu-158 ~]#awk 'BEGIN{print strftime("%Y-%m-%d %T:%M:%S")}'
2025-10-06 15:34:23:34:23
[root@ubuntu-158 ~]#awk 'BEGIN{print strftime("%Y-%m-%d %H:%M:%S");system("date \"+%Y-%m-%d %H:%M:%S\"")}'
2025-10-06 15:39:10
2025-10-06 15:39:10
自定义函数
function name ( parameter, parameter, ... ) {
statements
return expression
}
[root@ubuntu-158 ~]#awk 'function test(){print "hello world"}BEGIN{test()}'
hello world
[root@ubuntu-158 ~]#awk -F: 'function test(uname,uid){print uname" id is "uid}{test($1,$3)}' /etc/passwd
root id is 0
daemon id is 1
bin id is 2
sys id is 3
...
[root@ubuntu-158 ~]#vim test.awk
[root@ubuntu-158 ~]#cat test.awk
function max(x,y)
{
x>y?var=x:var=y
return var
}
BEGIN{print max(a,b)}
[root@ubuntu-158 ~]#awk -v a=30 -v b=50 -f test.awk
50
awk脚本
#
[root@ubuntu-158 ~]#cat a.awk
{print $1,$3}
[root@ubuntu-158 ~]#awk -F: -f a.awk /etc/passwd
root 0
daemon 1
bin 2
sys 3
#
[root@ubuntu-158 ~]#cat b.awk
#!/bin/awk -f
{print $1,$3}
[root@ubuntu-158 ~]#chmod a+x b.awk
[root@ubuntu-158 ~]#./b.awk -F: /etc/passwd
root 0
daemon 1
bin 2
sys 3
...
向awk脚本传递参数
awkfile var=value var2=value2... Inputfile
#说明
上面格式变量在BEGIN过程中不可用。直到首行输入完成以后,变量才可用
可以通过-v 参数,让awk在执行BEGIN之前得到变量的值
命令行中每一个指定的变量都需要一个-v参数
[root@ubuntu-158 ~]#awk -v x=100 'BEGIN{print x}{print x+100}' /etc/issue
100
200
200
[root@ubuntu-158 ~]#awk 'BEGIN{print x}{print x+100}' x=200 /etc/issue
300
300
[root@ubuntu-158 ~]#cat c.awk
#!/bin/awk -f
{if($3>=min && $3<=max)print $1,$3}
[root@ubuntu-158 ~]#chmod a+x c.awk
[root@ubuntu-158 ~]#./c.awk -F: min=100 max=200 /etc/passwd
dhcpcd 100
usbmux 101
pollinate 102
syslog 103
uuidd 104
tcpdump 105
tss 106
landscape 107
sshd 108
glances 109
postfix 110
三、文本处理工具
1、查看文本文件内容
① cat
#查看文本内容
cat [OPTION]... [FILE]...
#常见选项
-E|--show-ends #显示行结束符$
-A|--show-all #显示所有控制符
-n|--number #对显示出的每一行进行编号
-b|--number-nonblank #非空行编号
-s|--squeeze-blank #压缩连续的空行成一行
② nl
#显示行号,相当于cat -b
[root@ubuntu-158 ~]#cat test.txt
a
b
c
d
e
[root@ubuntu-158 ~]#nl test.txt
1 a
2 b
3 c
4 d
5 e
③ tac
#逆向显示文本内容,行倒序显示
#等待标准输入
[root@ubuntu-158 ~]#tac
a
bb
ccc 按ctrl+d结束
ccc
bb
a
[root@ubuntu-158 ~]#cat test.txt
a
b
c
d
e
[root@ubuntu-158 ~]#tac test.txt
e
d
c
b
a
[root@ubuntu-158 ~]#seq 5 | tac
5
4
3
2
1
④ rev
#将同一行的内容逆向显示,同一行倒序
[root@ubuntu-158 ~]#cat test.txt
a b c d e
1 2 3 4 5
[root@ubuntu-158 ~]#tac test.txt
1 2 3 4 5
a b c d e
[root@ubuntu-158 ~]#rev test.txt
e d c b a
5 4 3 2 1
#等待标准输入
[root@ubuntu-158 ~]#rev
abcedfg
gfdecba
[root@ubuntu-158 ~]#echo {1..5} | rev
5 4 3 2 1
2、查看非文本文件内容hexdump
hexdump 是一个用于显示文件二进制内容的命令行工具,可以将文件或输入数据以十六进制(hex)、ASCII、十进制(decimal)等形式格式化输出。它常用于调试、逆向工程或分析二进制文件(如可执行文件、图片、日志等)。
-C #规范格式(十六进制 + ASCII)
-b #单字节八进制(one-byte octal)
-c #单字节ASCII(one-byte character)
-d #双字节十进制(two-byte decimal)
-x #双字节十六进制(two-byte hexadecimal)
-n length #只读取前 length 字节
-s offset #从偏移量 offset 开始读取
-v #显示版本信息
[root@ubuntu-158 ~]#hexdump -C -n 512 /dev/sda
00000000 eb 63 90 00 00 00 00 00 00 00 00 00 00 00 00 00 |.c..............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000050 00 00 00 00 00 00 00 00 00 00 00 80 00 08 00 00 |................|
00000060 00 00 00 00 ff fa 90 90 f6 c2 80 74 05 f6 c2 70 |...........t...p|
00000070 74 02 b2 80 ea 79 7c 00 00 31 c0 8e d8 8e d0 bc |t....y|..1......|
00000080 00 20 fb a0 64 7c 3c ff 74 02 88 c2 52 bb 17 04 |. ..d|<.t...R...|
...
3、分页查看内容
① more
可以实现分页查看文件,可以配合管道实现输出信息的分页。
more [OPTIONS...] FILE...
#常用选项
-d #在底部显示提示
-s #压缩连续空行
#命令选项
空格键 #翻页
回车键 #下一行
!cmd #执行命令
h #显示帮助
:f #显示文件名和当前行号
= #显示行号
② less
less 也可以实现分页查看文件或STDIN输出,less 命令是man命令使用的分页器。
less [OPTIONS...] FILE...’
#常用选项
-e #显示完成后自动退出
-N #显示行号
-s #压缩连续空行
-S #不换行显示较长的内容
#命令选项
:h #显示帮助
/string #搜索
:!cmd #执行命令
b #向上翻
4、显示文本前面或者后面的行内容
① head
#可以显示文件或标准输入的前面行
head [OPTION]... [FILE]...
#常用选项
-c|--bytes=N #指定获取前N字节
-n|--lines=N #指定获取前N行,N如果为负数,表示从文件头取到倒数第N前
-N #同上
-q|--quiet|--silent #不输出文件名
-v|--verbose #输出文件名
-z|--zero-terminated #以NULL字符而非换行符作为行尾分隔符
② tail
#tail 和head 相反,查看文件或标准输入的倒数行
tail [OPTION]... [FILE]...
#常用选项
-c|--bytes=N #指定获取后N字节
-n|--lines=N #指定获取后N行,如果写成+N,表示从第N行开始到文件结束
-N #同上
-f|--follow=descriptor #跟踪显示文件fd新追加的内容,常用日志监控,当删除再新建同名文件,将无法继续跟踪
-F|--follow=name --retry #跟踪文件名,相当于--follow=name --retry,当删除文件再新建同名文件,可继续追踪
-q|--quiet|--silent #不输出文件名
-z|--zero-terminated #以NULL字符而非换行符作为行尾分隔符
tailf #类似 tail –f,当文件不增长时并不访问文件,节约资源,CentOS8已经无此工具
5、按列抽取文本cut
cut 命令可以提取文本文件或STDIN数据的指定列。
cut OPTION... [FILE]...
#常用选项
-b|--bytes=LIST #以字节分割,指定要显示的列
-c|--characters=LIST #以字符分割,指定要显示的列
-d|--delimiter=DELIM #指定分割符,默认是tab
-f|--fields=LIST #要显示的列,-f1, -f1,2,3, -f 1-3,4
-s|--only-delimited #不显示没有包括分割符的内容
--output-delimiter=STRING #输出的时候用指定字符代替分割符
-z|--zero-terminated #以 NUL 字符而非换行符作为行尾分隔符
#一个中文是三个字节,一个字符
6、合并多个文件paste
paste 合并多个文件同行号的列到一行。
paste [OPTION]... [FILE]...
#常用选项
-d|--delimiters=LIST #指定分割符,默认用TAB
-s|--serial #合成一行显示
-z|--zero-terminated #以 NUL 字符而非换行符作为行尾分隔符
[root@ubuntu2204 ~]# cat alpha.log
a
b
c
d
e
[root@ubuntu2204 ~]# cat seq.log
1
2
3
4
5
[root@ubuntu2204 ~]# cat alpha.log seq.log
a
b
c
d
e
1
2
3
4
5
[root@ubuntu2204 ~]# paste alpha.log seq.log
a 1
b 2
c 3
d 4
e 5
[root@ubuntu2204 ~]# paste -d":" alpha.log seq.log
a:1
b:2
c:3
d:4
e:5
[root@ubuntu2204 ~]# paste -s seq.log
1 2 3 4 5
[root@ubuntu2204 ~]# paste -s alpha.log
a b c d e
[root@ubuntu2204 ~]# paste -s alpha.log seq.log
a b c d e
1 2 3 4 5
[root@ubuntu2204 ~]# seq 10|paste -s -d+|bc
55
#批量修改密码
[root@ubuntu2204 ~]# cat user.txt
tom
jerry
[root@ubuntu2204 ~]# cat pass.txt
12345
54321
[root@ubuntu2204 ~]## paste -d: user.txt pass.txt
tom:12345
jerry:54321
[root@ubuntu2204 ~]# paste -d: user.txt pass.txt | chpasswd
7、分析文本工具
① 收集文本统计数据wc
wc 命令可用于统计文件的行总数、单词总数、字节总数和字符总数,可以对文件或STDIN中的数据统计。
wc [OPTION]... [FILE]...
#常用选项
-l|--lines #只计数行数
-w|--words #只计数单词总数
-c|--bytes #只计数字节总数
-m|--chars #只计数字符总数
-L|--max-line-length #显示文件中最长行的长度
② 文本排序sort
把整理过的文本显示在STDOUT,不改变原始文件。它可以按行对文本进行升序或降序排列,支持数字、字符串、日期等多种排序规则,并可结合其他命令(如 uniq、awk)进行数据处理。
sort [OPTION]... [FILE]...
#常用选项
-b|--ignore-leading-blanks #忽略文件中的空白
-f|--ignore-case #忽略大小写
-h|--human-numeric-sort #人类可读排序
-M|--month-sort #以月份排序
-n|--numeric-sort #以数字大小排序
-R|--random-sort #随机排序
-r|-reverse #倒序
-t|--field-separator=SEP #指定列分割符
-k|--key=KEYDEF #指定排序列
-u|--unique #去重
-z|--zero-terminated #以 NUL 字符而非换行符作为行尾分隔符
③ 去重uniq
uniq命令从输入中删除前后相接的重复的行,常和 sort 配合使用。
uniq [OPTION]... [INPUT [OUTPUT]]
#常见选项
-c|--count #显示每行出现次数
-d|--repeated #仅显示有重复行
-D #显示所有重复行具体内容
-u|--unique #仅显示不重复的行
-z|--zero-terminated #以 NUL 字符而非换行符作为行尾分隔符
④ 比较文件
diff
#diff 命令比较两个文件之间的区别
diff [OPTION]... FILES
#常用选项
-u #选项来输出“统一的(unified)”diff格式文件,最适用于补丁文件
[root@ubuntu-158 ~]#cat f1.txt
111
xxx
222
[root@ubuntu-158 ~]#cat f2.txt
ooo
xxx
888
ccc
[root@ubuntu-158 ~]#diff -u f1.txt f2.txt
--- f1.txt 2025-10-06 16:59:43.257051861 +0800
+++ f2.txt 2025-10-06 16:59:58.719943686 +0800
@@ -1,3 +1,4 @@ #比较结果 f1 3行 f2 4行
-111
+ooo
xxx
-222
+888
+ccc
#比较结果保存至文件
[root@ubuntu-158 ~]#diff -u f1.txt f2.txt > f.patch
[root@ubuntu-158 ~]#rm -rf f2.txt
#还原
[root@ubuntu-158 ~]#patch -b f1.txt f.patch
patching file f1.txt
#还原出来的是f2.txt,原先f1.txt被保存xxx.orig后缀文件
[root@ubuntu-158 ~]#cat f1.txt
ooo
xxx
888
ccc
[root@ubuntu-158 ~]#cat f1.txt.orig
111
xxx
222
patch
#patch 复制在其它文件中进行的改变(要谨慎使用)
patch [OPTION]... [ORIGFILE [PATCHFILE]]
#常用选项
-b|--backup #备份
[root@ubuntu-158 ~]#patch -b f1.txt f.patch
patching file f1.txt
#用f1.txt和 f.patch 生成一个名为f1.txt的文件,但内容是原来f2.txt文件中的内容,
#-b 选项则备份了现有的 f1.txt
vimdiff
#相当于vim -d
[root@ubuntu-158 ~]#which vimdiff
/usr/bin/vimdiff
[root@ubuntu-158 ~]#ll /usr/bin/vimdiff
lrwxrwxrwx 1 root root 25 Apr 16 01:29 /usr/bin/vimdiff -> /etc/alternatives/vimdiff*
[root@ubuntu-158 ~]#ll /etc/alternatives/vimdiff*
lrwxrwxrwx 1 root root 18 Apr 16 01:29 /etc/alternatives/vimdiff -> /usr/bin/vim.basic*
[root@ubuntu-158 ~]#ll /usr/bin/vim.basic*
-rwxr-xr-x 1 root root 5291608 Aug 28 03:47 /usr/bin/vim.basic*
cmp
#查看二进制文件不同
[root@ubuntu2204 ~]# ll /usr/bin/dir /usr/bin/ls
-rwxr-xr-x 1 root root 138208 Feb 8 2022 /usr/bin/dir*
-rwxr-xr-x 1 root root 138208 Feb 8 2022 /usr/bin/ls*
[root@ubuntu2204 ~]# ll /usr/bin/dir /usr/bin/ls -i
918119 -rwxr-xr-x 1 root root 138208 Feb 8 2022 /usr/bin/dir*
918278 -rwxr-xr-x 1 root root 138208 Feb 8 2022 /usr/bin/ls*
[root@ubuntu2204 ~]# diff /usr/bin/dir /usr/bin/ls
Binary files /usr/bin/dir and /usr/bin/ls differ
[root@ubuntu2204 ~]# cmp /bin/dir /bin/ls
/bin/dir /bin/ls differ: byte 25, line 1
#跳过前20个字节,观察后面10个字节
[root@ubuntu2204 ~]# hexdump -s 20 -Cn 10 /bin/ls
00000014 01 00 00 00 b0 6a 00 00 00 00 |.....j....|
0000001e
[root@ubuntu2204 ~]# hexdump -s 20 -Cn 10 /bin/dir
00000014 01 00 00 00 90 6a 00 00 00 00 |.....j....|
0000001e
1023

被折叠的 条评论
为什么被折叠?



