Linux Shell文本处理三剑客grep、sed、awk总结

目录

grep

sed工具

地址

基础命令:

高级编辑:

标签

awk

选项:

内置变量:

模式:

awk流程控制:

内置函数

I/O语句

自定义函数


grep

过滤来自一个文件或标准输入匹配模式内容。 除了 grep 外,还有 egrep、fgrep。egrep 是 grep 的扩展,相当于 grep -E。fgrep 相当于 grep - f,用的少。

用法:grep [OPTION]... PATTERN [FILE]...

常用选项:

  • -E:支持扩展正则表达式,默认支持基础正则表达式
  • -e:指定多个模式匹配,相当于或
  • -f:从文件每一行获取匹配模式
  • -i:忽略大小写
  • -w:模式匹配整个单词
  • -x:模式匹配整行
  • -v:打印不匹配的行
  • -o:只打印匹配的内容
  • -c:只打印每个文件匹配的行数
  • -n:打印行号
  • -A:打印匹配的后几行
  • -B:打印匹配的前几行
  • -C:打印匹配的前后几行

1)匹配多个模式

# echo "a bc de" |xargs -n1 |grep -e 'a' -e 'bc' a bc

2)去除空格 http.conf 文件空行或开头#号的行

grep -E -v "^$|^#" /etc/httpd/conf/httpd.conf

3)只显示匹配的字符串

# echo "this is a test" |grep -o 'is'
is
is

4)统计匹配多少行

# seq 1 20 |grep -c -E '[0-9]{2}'
11

5) 匹配所有 IP

# ifconfig |grep -E -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"

6)打印匹配结果及前 3 行

# seq 1 10 |grep 5 -B 3
2
3
4
5

sed工具

流编辑器,用于过滤和替换文本,以行为单位

工作原理:sed 命令将当前处理的行读入模式空间进行处理,处理完把结果输出,并清空模式空间(可以使用特殊命令不清除)。然后再将下一行读入模式空间进行处理输出,以此类推,直到最后一行。还有一个空间叫保持空间,又称暂存空间,可以暂时存放一些处理的数据,但不能直接输出,只能放到模式空间输出。 这两个空间其实就是在内存中初始化的一个内存区域,存放正在处理的数据和临时存放的数据。

用法:sed [选项] '地址 命令' file

常用选项

  • -n:使用安静模式,不打印模式空间,默认每次都会打印
  • -e:多次编辑、执行脚本、表达式来处理,相当于分号
  • -f:将sed的操作结果写在一个文件中
  • -r:使用扩展正则表达式的语法,默认是基础正则表达式
  • -i:直接修改文件的内容,比较危险

地址

1.单地址:

  • n:n为数字,表示处理单行
  • $:表示最后一行
  • /pattern/ :能够被此模式匹配到的每一行

2.地址范围:

  • 省略地址:对全文进行操作
  • n1,n2:从n1行到n2行
  • first~step:从first行开始,每次增加step行;1~2奇数行,2~2偶数行
  • first,+n:从first行开始,直到后面的n行
  • /pattern/,+n:打印匹配行和它的后n行

基础命令:

  • a:目前的下一行新增,后面接新增的字符,也可以用\开头
  • i:目前的上一行新增
  • d:删除行
  • p:打印
  • c:替换整行
  • s:替换字符,s///
  • =:打印当前行号
  • w /somefile:保存模式匹配的行至指定文件
  • r /somefile:读取指定文件的文本至模式空间中

1.匹配打印(p)

打印奇数行: seq 10 |sed -n '1~2p'

不打印最后一行: tail /etc/services |sed -n '$!p'

使用变量:tail /etc/services |sed -n ' '$a',3p';其中a是变量

sed 命令用单引号时,里面变量用单引号引起来,或者 sed 命令用双引号,因为双引号解释特殊符 号原有意义。

2.匹配删除(d)

去除空格 http.conf 文件空行或开头#号的行:

sed '/^#/d;/^$/d' /etc/httpd.conf

3.替换(s///)

[address]s/pattern/replacement/flags

flags用法如下:

flags标记功能
n1~512 之间的数字,表示指定要替换的字符串出现第几次时才进行替换,例如,一行中有 3 个 A,但用户只想替换第二个 A
g对数据中所有匹配到的内容进行替换,如果没有 g,则只会在第一次匹配成功时做替换操作,范围是一行。例如,一行数据中有 3 个 A,则只会替换第一个 A
p会打印与替换命令中指定的模式匹配的行。此标记通常与 -n 选项一起使用
w file将缓冲区中的内容写到指定的 file 文件中
&引用已匹配字符串
\n匹配第 n 个子串,该子串之前在 pattern 中用 () 指定
\转义(转义替换部分包含:&、\ 等)
I忽略大小写

tail /etc/services |sed 's/48049/&.0/' :表示把48049替换为48049.0

二次匹配替换:sed 's/blp5/test/;s/3g/4g/ ;也可以使用-e

高级编辑:

所有的 sed 命令都只是针对单行数据执行操作, 但是,有时我们需要对跨多行的数据执行特定操作。比如说,在文本中查找一串字符串"http://com",它很有可能出现在两行中,每行各包含其中一部分。

  • p:打印模式空间所有内容
  • P:打印模式空间开端至\n内容,即打印第一个\n前面的内容Print
  • n:读取匹配到的行的下一行覆盖至模式空间,预示着下一行提前进入,下一次就可以不读取下一行了,直接跳过
  • N:将下一行追加至模式空间,多行处理,Next
  • d:删除模式空间,开始下一个循环
  • D:如果模式空间包含换行符\n,删除第一个\n之前的内容。如果模式空间不包含\n,则会像发出d命令那样启动正常的新循环,Delete
  • h:把模式空间中的内容覆盖至保持空间
  • H:把模式空间中的内容追加至保持空间中
  • g:从保持空间取出数据覆盖模式空间
  • G:从保持空间取出内容追加至模式空间
  • x:把模式空间中的内容与保持空间中的内容进行互换
  • !:取反,否定
  • q:退出sed

1.读取下一行(n 和 N)

下一行加入到模式空间后,下一次不会读取它了

1)打印匹配的下一行:sed -n '/xx/{n;p};

因为n是覆盖,覆盖了匹配的xx,所以只输出下一行

2)打印偶数: seq 6 |sed -n 'n;p' ;

sed 先读取第一行 1,执行 n 命令,获取下一行 2,此时模式空间是 2,执行 p 命令,打印模式空 间。 现在模式空间是 2,sed 再读取 3,执行 n 命令,

3)打印奇数:seq 6 |sed 'n;d' ;

2.打印和删除模式空间第一行(P 和 D)

1)打印奇数:seq 6 |sed -n 'N;P'

读取第一行 1,执行 N 命令读取下一行并追加到模式空间,此时模式空间是 1\n2,执行 D 命令删除 模式空间第一行 1,剩余 2。

3.保持空间操作(h 与 H、g 与 G 和 x)

1)将匹配的内容覆盖到另一个匹配: seq 6 |sed -e '/3/{h;d}' -e '/5/g'

h 命令把匹配的 3 复制到保持空间,d 命令删除模式空间的 3。后面命令再对模式空间匹配 5,并用 g 命令把保持空间 3 覆盖模式空间 5。

标签

  • : lable name 定义标签
  • b lable 跳转到指定标签,如果没有标签则到脚本末尾
  • t lable 跳转到指定标签,前提是 s///命令执行成
# seq 6 |sed ':a;N;s/\n/,/;b a'
1,2,3,4,5,6 

看看这里的标签使用,:a 是定义的标签名,b a 是跳转到 a 位置。 sed 读取第一行 1,N 命令读取下一行 2,此时模式空间是 1\n2$,执行替换,此时模式空间是 1,2$,执行 b 命令再跳转到标签 a 位置继续执行 N 命令,读取下一行 3 追加到模式空间,此时模式 空间是 1,2\n3$,再替换,以此类推,不断追加替换,直到最后一行 N 读不到下一行内容退出。

awk

基本的命令语法:awk option '模式1 {操作1} 模式2 {操作2} …… ' file

awk倾向于一行当中分成数个字段来处理。默认的分割字符为空格和制表符tab。

选项:

  • -f:从文件读取awk程序源文件,文件内容应该是 模式+操作那部分
  • -F:指定字段分隔符
  • --posix :兼容 POSIX 正则表达式
  • -v var=value :定义变量并赋值,可以修改内置变量

内置变量:

变量名描述
FILENAME当前输入文档的名称
NR当前所处理的数据流是第几行数据
FNR当前输入文档的行号,在有多个输入文档时使用
NF当前记录(行)的总列数,字段数
FS字段分隔符,默认是空格或TAB
OFS多个字段输出分隔符,默认为空格,如print $1,$2表示$1和$2输出出来时的分隔符
RS输入记录分隔符,默认为换行符\n,就是将\n结尾的视为一条记录
ORS输出记录分隔符,默认为换行符\n,输出出来时各记录的分隔符
$0当前记录(行)的全部数据内容
$n当前行的第n个字段的内容
ARGC命令行参数数量
ARGV将命令行参数存到数组,元素由 ARGC 指定,数组下标从 0 开始

1.自定义变量

[root@com ~]# cat hosts 
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@com ~]# awk -v x="xx" -v y="${SHELL}" '{print x,y}' hosts
xx /bin/bash
xx /bin/bash

如果要直接使用环境变量,需要'{print " ' $SHELL' " }' ,双引号加单引号包起来,或直接使用一个单引号

awk中变量不需定义就可以直接使用,作为字符处理时未定义的变量默认值为空,作为数字处理时未定义的变量默认值为0

2.自定义分隔符

head -n 3 /etc/passwd | awk -F ":" '{print $1,$2}'
head -n 3 /etc/passwd | awk  'BEGIN{FS=":"}{print $1,$2}'

使用-F或BEGIN{FS=}

也可以使用多个分隔符:-F "[: ]" ,[ ]元字符的意思是符号其中任意一个字符

3.内置变量RS、OFS、ORS

RS:指定每条记录间的分隔符

awk -v RS="." '{print $1}' /tmp/hosts       #指定.作为行分隔符,当遇到.才把前面的数据视为一行,视为一条记录

OFS:指定输出的列之间的分隔符

[root@com ~]# awk -v OFS="\t-" '{print $1,$2}' hosts   #设置为TAB-
127.0.0.1   -localhost
::1 -localhost 

ORS:指定输出的记录之间的分割符

[root@com ~]# awk -v ORS="\t" '{print $1,$2}' hosts   #指定每条记录不换行,用tab分隔
127.0.0.1 localhost ::1 localhost   [root@com ~]# 

模式:

Pattern描述
BEGIN{}给程序赋予初始状态,先执行的工作
END{}程序结束之后执行的一些扫尾工作
/regular expression/为每个输入记录匹配正则表达式,全行匹配
~/regular expression/特定数据正则匹配
pattern && pattern逻辑 and,满足两个模式
pattern||pattern逻辑 or,满足其中一个模式
! pattern逻辑 not,不满足模式
pattern1, pattern2范围模式,匹配所有模式 1 的记录,直到匹配到模式 2

除了正则相关的,还支持非常多的运算:==、!=、>、<、?:、*= ……

#打印每行中有tcp的行:
awk '/tcp/{print $0}'
#打印每条记录第2列有tcp的行:
awk '$2~/tcp/{print $0}'
#打印第一列等于blp5或isnetserv的行
awk '$1=="blp5"||$1=="isnetserv"{print $0}'
#打印第10行的数据
awk 'NR==10{print $0}'
#统计有多少个客户端登录root
who | awk '$1=="root"{x++} END{print x}'    
#打印1~200之间能被6整除且包含数字6的整数数字
seq 200 | awk '$1%6==0 && $1~/6/'  

awk流程控制:

1)if语句:

if(判断条件){动作指令1;} [ else {动作指令2;} ]

#输出uid大于等于1000的行
cat /etc/passwd | awk 'BEGIN{FS=":"}{if($3>=1000)print $0}'
#带else
seq 5 |awk '{if($0==3)print $0;else print "no"}'

2)while语句:

#打印每个字段
awk 'BEGIN{FS=":"}{i=1;while(i<=NF){print $i;i++;}}'

3)for 语句 C 语言风格

awk '{for(i=1;i<=NF;i++)print $i}' file

4)for 语句遍历数组

[root@com ~]# awk 'BEGIN{a[0]=1;a[2]=2;a["n"]=3;for(i in a){printf i"---"a[i]"\n"}}'
n---3
0---1
2---2

5)中断

与shell类似,awk提供了continue、break、exit循环中断语句

awk 'BEGIN{for(i=1;i<=5;i++){if(i==3){break};print i}}'

内置函数

函数描述
int(expr)截断为整数,可以对小数取整
sqrt(expr)平方根
rand()返回0到1之间的随机数,0 < N < 1
srand([expr])使用 expr 生成随机数,如果不指定,默认使用当前时间为种子,如果前面有种子则使用生成随机数
asort(a, b)对数组 a 的值进行排序,把排序后的值存到新的数组 b 中,新排序 的数组下标从 1 开始
asorti(a,b)对数组 a 的下标进行排序,同上
sub(r, s [, t])将字符串t中与正则表达式r匹配的字符串全部替换为s,但仅替换第一个匹配的字符串,而不是替换全部
substr(s, i [, n])截取字符串 s 从 i 开始到长度 n,如果 n 没指定则是剩余部分
gsub(r, s [, t])将字符串t中所有与正则表达式r匹配的字符串全部替换为s,如果没有指定字符串t,则默认对$0进行替换操作
gensub(r, s, h [, t])对输入的记录用 s 替换 r 正则匹配,h 替换指定索引位置
index(s, t)返回 s 中字符串 t 的索引位置,0 为不存在
length([s])返回 s 的长度,如果不指定字符串s则统计$0的长度
match(s, r [, a])根据正则表达式r返回其在字符串s中的位置坐标,如果不包含返回 0
split(s, a [, r [, seps]])根据分隔符 seps 将 s 分成数组 a,如果没指定分隔符,则使用IFS定义的。
tolower(str)str 中的所有大写转换成小写
toupper(str)str 中的所有小写转换成大写
systime()当前时间戳
strftime([format [, timestamp[, utcflag]]])格式化输出时间,将时间戳转为字符串

1)int取整

# echo -e "123.11\n123abc\nabc123" | awk -v ORS="  " '{print int($0)}END{print "\n"}'
123  123  0 

2)rand()和 srand()

#awk '{srand();print rand() }'
0.447679
#awk 'BEGIN{srand();print int(rand()*10)}'
4

3)asort()

#awk 'BEGIN{a[0]=2;a[1]=13;a[3]=8;a["nihao"]=1;s=asort(a,b)}END{for(i=1;i<s;i++){print b[i]}} '
1
2
8
#awk 'BEGIN{a[0]=2;a[1]=13;a[3]=8;a["nihao"]=1; s=asort(a,b)}END{for(i in b){print b[i]}} '
13
1
2
8

4)sub()和 gsub()

替换正则匹配的字符串:
# tail /etc/services |awk '/blp5/{sub(/tcp/,"icmp");print $0}'
blp5 48129/icmp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
# tail /etc/services |awk '/blp5/{gsub(/c/,"9");print $0}'
blp5 48129/t9p # Bloomberg lo9ator
blp5 48129/udp # Bloomberg lo9ator

4)index

# echo "abc" |awk '{print index($0,"bc")}'
2

5)match

# echo "123abc#456cde 789aaa#234bbb 999aaa#aaabbb" |xargs -n1 |awk '{print 
match($0,234)}' 
0
8
0

6)split

# echo "abc:def:ghi" | awk '{split($0,a,":");for(i=1;i<=length(a);i++)print a[i]}'
abc
def
ghi

7)substr

# echo "abcdefg" | awk '{print substr($0,3)}'
cdefg

8)时间处理

# echo 1 | awk 'BEGIN{print systime()}'
1652773555
# echo 1 | awk 'BEGIN{print systime()}' | awk '{print strftime("%Y-%m-%d %H:%M:%S",$0)}'
2022-05-17 15:05:36

I/O语句

语句描述
getline读取下一个输入记录设置给$0
getline var读取下一个输入记录并赋值给变量 var
command | getline [var]运行 Shell 命令管道输出的数据的第一行给到$0 或 var
next停止当前处理的输入记录后面动作
print打印当前记录
printf fmt, expr-list格式化输出
system(cmd-line)可以直接在awk中调用shell命令,会启动一个新shell进程执行命令

1)getline :

能让awk立刻读取下一行数据(读取下一条记录并复制给$0,并重新设置NF、NR和FNR);getline var不会复制给$0

# seq 5 | awk '/3/{print;getline;print $0;}'
3
4
# seq 5 | awk '{getline a;print a;}' 
2
4
4

2)next:

停止处理当前的输入记录,立刻读取下一条记录并返回awk程序的第一个模式匹配重新处理数据。有点类似于循环语句中的continue,不会执行当次循环的后续语句

3)system:

# awk 'BEGIN{if(system("grep root /etc/passwd &>/dev/null")==0)print "yes";else print "no"}'
yes

4)printf格式:

Format描述
%s字符串
%d,%i小数
%f浮点数
%.ns输出字符串,n 是输出几个字符
%m.nf输出浮点数,m 是输出整数位数,n 是输出的小数位数
%x (%X)不带正负号的十六进制,使用 a 至 f 表示 10 到 15 , %X使用 A 至 F 表示 10 至 15
%%输出单个%
%-5s左对齐,对参数每个字段左对齐,宽度为 5
%-4.2f左对齐,宽度为 4,保留两位小数
%5s右对齐,不加横线表示右对齐

自定义函数

格式:function name(parameter list) { statements }

# awk 'function myfunc(a,b){return a+b}BEGIN{print myfunc(1,2)}'
3

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值