目录
特殊字符
元字符 | 含义 | 案例 |
. | 匹配任意单个字符 | a.b可以匹配字符串"abc"、"aac"、"acc"等 |
^ | 匹配字符串的开头 | ^abc可以匹配以abc开头的字符串,如"abcdef" |
$ | 匹配字符串的结尾 | $abc可以匹配以abc为结尾的字符串,如"123abc" |
* | 匹配前面的字符零次或多次 | 1、*.txt表示匹配.txt为结尾的文件 2、a*b 可以匹配"aab"、 "aabb"、 "asdfb" 等等 |
+ | 匹配前面的字符一次或多次 | 匹配连续的数字:echo "123456" | grep -E "[0-9]+" |
? | 匹配前面的字符零次或一次 | 1、colou?r 匹配color或colour 2、.?匹配零个或一个任意字符 |
{n} | 匹配前面的字符恰好n次 | 1、a{3} 表示连续出现3个a,即aaa 2、[0-9]{2} 表示连续出现两个数字 |
{n,} | 匹配前面的字符至少n次 | 1、a{2,}表示前面的字符a必须出现2次 2、[0-9]{3,}表示匹配至少三位数 |
{n,m} | 匹配前面的字符至少n次,但不超过m次 | b{2,3}a表示前面的字符"b"必须重复出现2到3次,并且后面紧跟着字符"a" |
[ ] | 1、匹配方括号内的任意一个字符 2、方括号中可以使用反向引用符(^)表示匹配除指定字符以外的任何字符。 3、方括号也可以包含一些转义字符 | 1、[abc]表示匹配a,b,c中的任意一个 2、 3、 4、[^abc]表示匹配除了字符a、b、c以外的任意字符 5、[\t]表示匹配制表符 |
| | 匹配两个或多个分支之一 | pattern1|pattern2 表示匹配模式pattern1或pattern2。 |
() | 标记一个子表达式的开始和结束位置 | 可以分组和控制优先级 |
命令行工具:grep、sed、awk
这三个工具通常可以结合管道 |
和重定向符号 >
、>>
等一起使用,组合出强大的文本处理能力。
grep
grep是一种文本搜索工具,它可以在文件中查找匹配某个模式的行,并将匹配的行输出到屏幕上。grep支持正则表达式,可以行进高级搜索。
语法
grep [options] pattern [files]
即:grep [选项] [字符串或正则表达式] [文件名]
常用选项:
-i
:忽略大小写进行匹配
-v
:反向查找,只打印不匹配的行
-n
:显示匹配行的行号
-r
:递归查找子目录中的文件
-l
:只打印匹配的文件名
-c
:只打印匹配的行数
-o
:只显示匹配到的部分
-E
:使用正则表达式
pattern:
\b为单词锁定符,如 '\bhello' 从左往右匹配hello,如 '123' 从右往左匹配123,如 '/b123/b' 只匹配123
一些字符在pattern中有特殊含义,若想匹配需要用到转义字符“\”。例如:grep '\$' test.txt 即查找'$'。特殊字符有 \\ \ ' '' $ | ^等
细节:
1、默认情况下,grep命令区分大小写。忽略大小写可以用-i选项
2、若搜索字符串包含空格需要用引号将其括起
3、如果使用扩展正则表达式,特殊符号是不用使用转义字符\
例:grep "2\{1,3\}" file.txt (需要转义字符)
grep -E "2{1,3}" file.txt (正则表达式,不需要转义字符)
案例
1、匹配test.txt文件中的字符串"hello"。
grep hello test.txt
2、匹配字符串"abcabcabc"中的所有"ab"。
echo abcabcabc | grep "\(ab\)\{1\}"
"\"表示转义字符,{1}表示ab恰好1次
3、找出ens33的ip地址、子网掩码、广播地址,即下图红框部分。
ifconfig ens33 | grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
[0-9]表示0到9的数字,{1,3}表示0到9的数字最少出现1次,最多出现3次,\.表示字符 “ . ”
4、test.txt文件中有三行字符串,“123456789@qq.com”、“1234567890@123.com”、“123qwedsf”,筛选出带有“@”的邮箱地址。
cat test.txt | grep -E "[0-9a-z]+@[0-9a-z]+\.com"
[0-9a-z]表示可以包含所有的数字所有的小写字母
5、查找“ifconfig ens33”命令结果中的1-255之间的整数
ifconfig ens33 | grep -Eo "\b([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b"
其中“|”表示或的意思。1-255可以分为几种情况讨论,[1-9]表示个位数,[1-9][0-9]表示十位数,1[0-9][0-9]表示100~199的数,2[0-4][0-9]表示200~249的数,25[0-5]表示250~255的数。
6、显示/etc/passwd当中,所有已sh为结尾的行
cat /etc/passwd | grep -E "sh$"
7、匹配/etc/inittab中的所有以s开头,而且d为结尾的单词
cat /etc/inittab | grep '\bs[a-z]*d\b'
用单词锁定符“\b”
8、已知test.txt文件中有三行:“987-123-4567”、“987 456-1230”、“(123) 456-7890”。用grep全部筛选出来
cat test.txt | grep -E "^(\([0-9]+\)|[0-9]+)[ -]?[0-9]+[- ]?[0-9]+"
[0-9]表示任意数字,\([0-9]+\)表示括号加任意数字,即“(任意数字)”。^(\([0-9]+\)|[0-9]+)表示“ [0-9] ”或“([0-9])”为开头。[ -]?表示空格或 “-” 的其中的一个。
9、高亮显示/etc/passwd文件中的冒号,及其两侧的字符
cat /etc//passwd | grep -E ".?:*:.?"
sed
sed是一种流编辑器,它可以从输入流(例如文件或管道)中读取文本,并对其进行操作。sed通常用于对文本进行替换或删除操作,也可以进行插入、追加和编辑等操作。
语法
sed [选项] '动作' 文件
选项参数
-n:禁止自动打印模式空间的内容
-e:允许对输入应用多条 sed 命令。以选项中指定的script来处理输入的文本文件
-f:以选项中指定的script文件来处理输入的文本文件
-i:直接修改文件内容,而不是在标准输出上显示结果。(没有这个选项只是显示而不影响文件)
-h:显示帮助
-v:显示版本信息
-r:表示使用扩展正则表达式
动作:
替换:s/old/new/,用 new 来替换每一行中第一个匹配到的 old。
删除:d,删除指定条件的行
插入:i\text,在指定位置插入文本
打印:p,打印符合条件的行,通常 p 会与参数 sed -n 一起运行
替换标记:g,用于替换所有匹配到的内容
新增:a, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)
取代:c,c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行
示例:
替换文本:sed 's/old/new/g' file.txt
删除匹配行:sed '/pattern/d' file.txt
多个操作组合:sed -e 's/foo/bar/' -e '/pattern/d' file.txt
sed -f 1.txt 2.txt 意思是
使用 sed
工具,并且将 1.txt
文件中的命令和正则表达式应用到目标文件 2.txt
上,从而实现修改操作。在执行时,sed
依次读取脚本文件中的每一行,并对目标文件进行修改,最终将修改结果输出到标准输出(终端)上。
需要注意的是,这个命令不会修改原始文件,而是将结果输出到标准输出上。如果想要将结果写回到原始文件中,可以使用 -i
选项
案例
1、打印/etc/passwd
sed ' ' /etc/passwd 或 cat /etc/passwd | sed ' '
2、用sed打印test.txt文件
sed -n 'p' test.txt
命令 sed -n 'p' test.txt 将会将文件 test.txt 中的每一行都打印(输出)出来。由于使用了 -n
选项,所以只会显示经过 sed 处理后的结果,不会显示原始文件的内容。这个命令等同于 cat test.txt
,因为它只是简单地打印文件的内容而已,没有进行任何修改或过滤操作。
3、打印test.txt文件中包含字母‘o’的行
sed -n '/o/p' test.txt
/o/是一个正则表达式,表示匹配包含字母 "o" 的行
4、打印在文件 /etc/passwd 中查找以 "root" 开头的行
sed -n '/^root/p' /etc/passwd
5、在 /etc/passwd 文件中从第四行开始寻找,一直到第一个以 "bash" 结尾的行,并将这个范围内的行打印出来。
sed -n '4,/bash$/p' /etc/passwd
6、在文件 /etc/passwd 中查找包含连续出现两次或更多次 "99:" 的字符串的行,并将这些符合条件的行打印出来。
sed -r -n '/(99:){2,}/p' /etc/passwd
/(99:){2,}/ 是一个正则表达式,表示匹配连续出现两次或更多次 "99:" 的字符串。
7、打印/etc/passwd 文件中要么root开头,要么bash结尾的行
sed -r -n '/^root|bash$^C' /etc/passwd
8、删除文件test1.txt所有的行
sed -i 'd' test1.txt
9、删除文件test1.txt的第三行和第七行
sed -i '3d;7d' test1.txt
3d;7d 表示删除第三行到第七行。如果是删除第三行到第七行,则用逗号,sed -i '3d,7d' test1.txt
10、删除空行
sed -i '/^$/d' test1.txt
/^$/ 表示匹配一个空行
11、在文件 test02.txt 的最后一行后面追加文件 test01.txt 的内容
sed '$r test01.txt' test02.txt
$表示最后一行。若想在特定的行下插入,则改为 sed '/特定的行/r test01.txt' test02.txt
r test01.txt是sed的一个命令,用于读取文件 test01.txt 的内容,并将其追加到指定位置。
由于没有加 -i 选项,所以这个命令不会修改原始文件,而是将结果输出到标准输出(终端)。
12、在test.txt文件内新增“123456”字符串
sed '$a 123456' test.txt
13、将字符串 “aaabbbcccddd” 替换成 “cccbbbaaa”
echo aaabbbcccddd | sed -r 's/(aaa)(bbb)(ccc)(ddd)/\3\2\1/'
s/(aaa)(bbb)(ccc)(ddd)/\3\2\1/ 是替换命令,用于匹配并替换字符串中的内容
(aaa)(bbb)(ccc)(ddd) 是一个正则表达式,用括号分组表示四个部分:aaa、bbb、ccc、ddd
\3\2\1 表示替换后的字符串,按照之前的分组顺序进行替换
awk
awk是一个强大的文本编辑器,逐行读取文件内容,然后输出结果。它可以读取输入流中的行,并根据指定的规则将它们分成不同的字段。然后可以对这些字段进行操作,如打印或计算。awk本身也是一个开发工具,内置代码,和java很像。
语法
awk [选项] '条件{动作}' 文件名
其中,[选项]
可以省略,'条件 {动作}'
是 awk 的脚本部分,文件名
是需要处理的文件名。
常用选项:
-F:指定字段分隔符。
-v:定义变量。
-f:从指定文件中读取 awk
脚本。
常用的内置函数:
length(str):返回字符串str的长度。
substr(str,start,length):返回字符串 str 从第 start 个字符开始,长度为 length 的子字符串。
split(str,arr,sep):将字符串 str 按照分隔符 sep 分割成数组 arr。
match(str,reg):在字符串 str 中查找正则表达式 reg,返回匹配的位置和长度。
常用变量:
$0:表示当前行。
$n:当前记录的第n个字段,字段间由FS分隔。
NF:表示当前行的字段数。
NR:表示当前行号。
OFS:输出字段分隔符,默认值与输入字段分隔符一致。
案例
1、打印文件 test01.txt 内容
awk '{print}' test01.txt
awk '0{print}' test01.txt 中的0表示始终为假,即不匹配任何行。由于条件不成立,因此不会执行动作部分,即不会打印任何内容。
awk '1{print}' test01.txt 中的1表示始终为真,即匹配所有行。
2、打印文件 test01.txt
中的所有行,并在每行前面添加行号。
awk '{print NR,$0}' test01.txt
print NR,$0 表示打印当前行的行号和内容。
3、打印文件 test01.txt
中的第三行。
awk 'NR==3{print}' test01.txt
条件为 NR==3
,即当前行号等于 3。
打印文件 test01.txt
中的第三行和第五行:awk 'NR==3;NR==5{print}' test01.txt
打印文件 test01.txt
中的第三行到第五行之间的内容:awk '(NR>=3)&&(NR<=5){print}' test01.txt
打印文件 test01.txt
中的偶数行:awk 'NR%2==0{print}' test01.txt
4、计算并打印出数值表达式 2的3次方 的结果。
awk 'BEGIN{print 2**3}' 或 awk 'BEGIN{print 2^3}'
5、从系统用户信息文件 /etc/passwd
中查找以 root
开头的行并打印出来。
awk '/^root/{print}' /etc/passwd
/^root/ 是一个正则表达式,表示匹配以 root 开头的行。
6、从系统用户信息文件 /etc/passwd
中查找包含 root
到 operator
之间的所有行,并将它们打印出来。
awk '/root/,/operator/{print}' /etc/passwd
7、用 BEGIN 统计 test01.txt 文件中的行数并打印出来。
awk 'BEGIN{x=0};{x++};END{print x}' test01.txt
BEGIN{x=0}
: 在处理输入之前执行的代码块。这里将变量 x
的初始值设置为 0。
{x++}
: 对每一行执行的代码块。这里将变量 x
的值加一,相当于统计行数。
END{print x}
: 在处理完整个输入之后执行的代码块。这里打印变量 x
的值,即行数。
8、从 /etc/passwd
文件的前五行中提取出每行的第五个字段,并将提取的结果打印出来。
head -n 5 /etc/passwd | awk 'BEGIN{FS=":"};{print $5}'
'BEGIN{FS=":"}'
: awk脚本的开始部分,在处理输入之前执行的代码块。这里设置字段分隔符为冒号 :
,以便后续按字段提取数据。
9、从 /etc/passwd
文件中查找 shell 为 bash 的用户,并打印出这些用户的用户名和家目录路径。
awk -F: '$7~"bash" {print $1,$NF}' /etc/passwd
-F:
选项,指示 awk
使用冒号 ‘ : ' 作为字段分隔符
$7~"bash"
:条件语句,用于判断当前行的第七个字段(即 shell 字段)是否包含字符串 "bash"。其中,~
表示模式匹配,$7
表示当前行的第七个字段,"bash" 是要匹配的模式。
{print $1,$NF}
:执行语句,如果条件语句成立,则执行该语句。这里打印当前行的第一个字段(即用户名)和最后一个字段(即家目录路径)。
同样的,不是 "nologin" 的用户:awk -F: '$7!~"nologin" {print $5}' /etc/passwd
10、查找家目录为 "/home/dn",且 shell 为 "/bin/bash" 的用户。
awk -F: '($6=="/home/dn") && ($7=="/bin/bash") {print $1,$NF}' /etc/passwd
11、筛选出 UID 大于 500 的用户。
awk -F: '{if ($3>500) {print $NF}}' /etc/passwd
12、从 /etc/passwd
文件中找出 UID 和 GID 中较大的值,然后将该最大值和整行内容打印出来。
效果如下:
awk -F: '{max=($3>$4)?$3:$4;{print max,$0}}' /etc/passwd
'{max=($3>$4)?$3:$4;{print max,$0}}'
:是一个awk的三元表达式。($3>$4)?$3:$4
是一个条件表达式。($3>$4) 为条件,条件为真则 $3 ,为假则 $4 ,即
比较第三个字段(UID)和第四个字段(GID),如果 UID 大于 GID,则将 UID 赋值给变量 max
,否则将 GID 赋值给 max
。然后使用 print max,$0
打印 max
和整行内容。
13、写脚本,计算并打印变量a加变量b的值。
14、以“用户名==UID”的形式输出
awk -v FS=':' -v OFS='==' '{print $1,$3}' /etc/passwd
-v FS=':'
:选项,指示 awk
使用冒号作为字段分隔符,并将其存储在变量 FS
中。
-v OFS='=='
:选项,指示 awk
使用双等号作为输出字段分隔符,并将其存储在变量 OFS
中。
15、awk数组
awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[0]}'
'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[0]}'
:在开始处理之前(即 BEGIN
部分),执行的 awk
脚本代码。在这段代码中,我们创建了一个名为 a
的数组,并分别给数组的索引 0
、1
、2
赋值为 10
、20
、30
。然后使用 print
命令打印数组 a
的第一个元素,即 a[0]
。
16、遍历数组
awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a)print i,a[i]}'
17、test.txt文件中有数个aaa、bbb和ccc字段。用awk分别统计它们的个数。
awk '{a[$1]++};END{for(i in a){print i,a[i]}}' test.txt
'{a[$1]++}'
:在每一行应用的 awk
脚本代码。$1
表示当前处理的行的第一个字段,即将其作为键存储到数组 a
中。a[$1]++
表示对数组 a
中以 $1
为键的元素的值进行自增操作,相当于统计了 $1
出现的次数。
END{for(i in a){print i,a[i]}}
:在文件处理完成之后(即 END
部分),执行的 awk
脚本代码。这段代码使用 for
循环遍历数组 a
,并使用 print
命令打印每个键值对。其中,i
表示数组 a
的键,a[i]
表示键 i
对应的值,即出现的次数。
能达到类似效果的还有:cat test.txt | sort | uniq -c
18、显示排除了 tmpfs
文件系统的磁盘的可用容量。
df | grep -v 'tmpfs' | awk '{sum+=$4} END{print "磁盘的可用容量:" sum/1024/1024"G"}'
grep -v 'tmpfs'
:过滤掉包含字符串 tmpfs
的行。
{sum+=$4}
:在每一行中,将第四个字段(即可用容量)加入变量 sum
中。
END{print "磁盘的可用容量:" sum/1024/1024"G"}
:在处理完所有行之后,使用 print
命令打印磁盘的可用容量。其中,sum/1024/1024
表示将 sum
的值从字节转换为以 GB 为单位的容量值,G
表示 GB 单位的后缀。
19、计算 /etc/
目录下所有普通文件的总大小。
ls -l /etc/ | awk '/^-/ {sum+=$5} END{print "文件总大小:"sum/1023"M"}'
/-/
:使用正则表达式匹配第一列以 -
开头(即普通文件)的行。
{sum+=$5}
:在每个匹配的行中,将第五列(即文件大小)加入变量 sum
中。
END{print "文件总大小:"sum/1023"M"}
:在处理完所有行之后,使用 print
命令打印文件的总大小。其中,sum/1023
表示将 sum
的值从字节转换为以 MB 为单位的大小值,M
表示 MB 单位的后缀。