shell文本处理工具sed和awk

发布时间 2023-05-25 18:08:58作者: 村尚chun叔

一、sed

1. sed的工作流程

image

  • 首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。
  • sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。
  • Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

2. sed使用方法

sed [option]  'sed的命令|地址定位' filename

说明:引用shell script中的变量应使用双引号,而非通常使用的单引号
option:
-e 	进行多项编辑,即对输入行应用多条sed命令时使用  sed -ne "/bash$/=" -ne "/bash$/p" 2.txt 
-n 	取消默认的输出
-f 	指定sed脚本的文件名
-r 	使用扩展正则表达式
-i 	原地编辑,修改源文件    -i和-n不要一起连用, -i和p不要连用
sed的命令:
/ / 	要进行匹配必须使用/ /将内容包起来
! 	对所选行以外的所有行应用命令,放到行数之后    5!d 除了第五行外都删除
p 	打印   sed -n '1,3p' 1.txt 
d 	删除   sed '1,3d' 1.txt   删除1-3行    sed '1d;3d' 1.txt 删除第一行和第三行
i 	在当前行之前插入文本。多行时除最后一行外,每行末尾需用"\"续行  vim——>O  sed 'i hello world' 1.txt
a	在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行 vim——> o  sed 'a hello' 1.txt
c	用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用"\"续行  整行替换   sed '/[a-z]/c hello' 1.txt    1,5c hello表示将1-5行替换为一个hello
r 	从文件中读取输入到指定位置下一行  sed '1r /etc/hosts' 2.txt  将/etc/hosts内容输入到2.txt的第一行下面
w 	将所选的行写入文件  sed '1,3w a.txt'  2.txt   将2.txt中的1-3行保存到a.txt中
s 	用一个字符串替换每行中的第一个匹配到的字符串   分隔符默认是/  可以自定义
g 	在行内进行全局替换  sed -n 's/[/:\.]//gp' 2.txt   将2.txt中的/ : .这三个符号替换为空 
& 	保存查找串以便在替换串中引用 == \(\) \1  sed -n 's/ro ot/& hello/gp'  2.txt  保存root,将root替换为root hello
= 	打印行号  sed '/bash$/=' 2.txt 打印以bash结尾的行号
x  	指定x行号
x,y 	指定x到y行号
/key/ 	查询包含关键字的行
/key1/,/key2/ 	匹配包含两个关键字之间的行
/key/,x 从匹配关键字的行开始到文件第x行之间的行(包含关键字所在行)
x,/key/ 从第x行开始到与关键字的匹配行之间的行
x,y! 	不包含x到y的行

举例:
注释掉1-5行  sed '1,5s/^/#&/gp' 2.txt       sed '1,5s/\(^\)/#\1/gp' 2.txt
去掉文件中以# $ ; \t# \t$ 开头的行   sed -r '/^(#|;|$|\t#|\t$)/d' smb.conf
y 	与tr类似,字符按照一对一的方式从左到右进行转换
正则表达式元字符对y命令不起作用,与s命令的分隔符一样,斜线可以被替换成其他的字符  y/xxx/xxx/   sed '39,41y/stu:x/STU@%/' /etc/passwd
q 	退出 sed '3q' 2.txt   sed查询到第三行结束就退出查询
sed '/foo/,+4d' 1.txt 删除从匹配字符串foo开始到其后四行为止的行
sed '/foo/,~3d' 1.txt 从匹配字符串foo开始,删除3的倍数行
sed '1~5d' file 从第一行开始删每五行删除一行
sed -nr '/foo|bar/p' 1.txt 显示匹配字符串foo或bar的行
sed -n '/foo/,/bar/' 1.txt 显示匹配从foo到bar的行
sed '1~2d' 1.txt 删除奇数行
sed '0~2d' 1.txt 删除偶数行
执行脚本命令 sed -f name.sed file或./name.sed file
脚本第一行写 #!/bin/sed -f 内容为sed命令中' '中的内容
sed 's/.//' a.txt	删除每一行中的第一个字符
sed 's/.//2' a.txt	删除每一行中的第二个字符
sed 's/.//N' a.txt	从文件中第N行开始,删除每行中第N个字符(N>2)
sed 's/.$//' a.txt	删除每一行中的最后一个字符

二、awk

1.awk介绍

awk的处理文本和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。

awk执行脚本命令  awk -f awk.sh file或./awk.sh file
脚本第一行写 #!/bin/awk -f   内容为awk命令中' '中的内容   不需要用引号保护命令,多个命令用分号间隔

2.awk使用方式

awk [option] 'commands' 文件名

option:
-F 定义字段分割符,默认的分隔符是空格
-v 定义变量并赋值  awk -v num=3 '{print num}' 2.txt
commands:
正则表达式,地址定位
'/root/{awk语句}'  'NR=1,NR=5{awk语句}'   '/^root/,/^ftp/{awk语句}'  'NR=5{print $0}'
{awk语句1;awk语句2...}   '{print $0;print $1}'

BEGIN...END...
'BEGIN{awk语句};{处理中};END{awk语句}'
'BEGIN{awk语句};{处理中}'
'{处理中};END{awk语句}'

awk内部变量
$0 		当前处理行的所有记录
$1,$2,$3……$n 	文件中每行以间隔符合分割的不同字段 awk -F: '{print $1,$3}'
NF 		当前记录的字段数(列数)  awk 'NR=1,NR=5{print $0}' 2.txt == awk 'NR=1,NR=5' 2.txt
$NF 		最后一列   $(NF-1)倒数第二列    awk -F: '/^root/,/^lp/{print $1"的默认shell是:"$NF}' 2.txt   打印出来的内容想用什么来间隔,用" "引起来
FNR/NR 		行号
FS 		定义间隔符 awk 'BEGIN{FS=":"};/^root/,/^lp/{print $1,$NF}' 2.txt
OFS 		定义输出字段分隔符,默认空格  awk -F: 'BEGIN{OFS="的默认shell是:"};/^root/,/^lp/{print $1,$NF}' 2.txt
RS 		输入记录分隔符,默认换行 awk 'BEGIN{RS="\t"};{print $0}' 2.txt
ORS 		输出记录分隔符,默认换行 awk 'BEGIN{ORS="\t"};{print $0}' 2.txt        
FILENAME 	当前输入的文件名

{printf %-15s %-20s %-20s\n,$1,$NF}  美化格式左对齐15个字符
%s 字符类型 string
%d 数值类型
- 左对齐
echo == print
echo -n	== printf  默认不会在行尾自动换行,加\n

正则表达式
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
~ 匹配
!~ 不匹配
! 逻辑非
&& 逻辑与
|| 逻辑或

打印以root开头或以lp开头的行
grep: grep -E '^root|^lp' 2.txt
sed: sed -nr '/^root|^lp/p' 2.txt  ==  sed -n '/^root/p;/^lp/p' 2.txt
awk: awk '/^root/||/^lp/' 2.txt  ==  awk '/^root/||/^lp/{print $0}' 2.txt
awk中  /^root/||/^lp/ == /^root|^lp/ == /^root/;/^lp/
变量 变量说明 备注
$0 当前处理行的所有记录
$1,$2,$3...$n 文件中每行以间隔符号分割的不同字段 awk -F: '{print $1,$3}'
NF 当前记录的字段数(列数) awk -F: '{print NF}'
$NF 最后一列 $(NF-1)表示倒数第二列
FNR/NR 行号
FS 定义间隔符 'BEGIN{FS=":"};{print $1,$3}'
OFS 定义输出字段分隔符,默认空格 'BEGIN{OFS="\t"};print $1,$3}'
RS 输入记录分割符,默认换行 'BEGIN{RS="\t"};{print $0}'
ORS 输出记录分割符,默认换行 'BEGIN{ORS="\n\n"};{print $1,$3}'
FILENAME 当前输入的文件名