linux shell sed&awk

简述

vim 与 sed&awk 的区别:

  1. 交互式与非交互式
  2. 文件操作模式与行操作模式

sed

sed是一种流编编器,它是文本处理中非常中的工具,能够完美的配合正则表达式便用,功物能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为”模式空间”( oattern space),接看用sed命令处理缓冲区中的内容,处理成后,把缓冲区的内容送往屏幕显示。

sed 会根据脚本命令来处理文本文件中的数据,这些命令要么从命令行中输入,要么存储在一个文本文件中,sed的基本工作方式如下:
1 每次仅读取一行内容;(将文件以行为单位读取到内存(模式空间))
2 根据提供的规则命令匹配并修改数据(sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区中的数据;)
3 将执行结果输出。
当一行数据匹配完成后,它会继续读取下一行数据,并重复这个过程,直到将文件中所有数据处理完毕。

语法: sed [选项] [脚本命令] 文件名
第一种形式:stdout | sed [option] “pattern command”
第二种形式:sed [option] “pattern command” file

常见命令参数:
p==print
d:delete
=:打印匹配行的行号
-n 取消默认的完整输出,只要需要的 (会自动输出处理后的内容,而该选项会屏蔽启动输出,需使用 print 命令来完成输出。)
-e 允许多项编辑 (该选项会将其后跟的脚本命令添加到已有的命令中。)
-i 修改文件内容
-r 不需要转义

注意:& 符号在sed命令中代表上次匹配的结果

基本使用示例

$ echo a a a > afile
## 只替换第一次出现的a字符
$ sed 's/a/aa/' afile
# 结果  aa a a
## sed 替换特殊字符时 s/a/aa/ 这种格式可以替换称为 s!a!aa  (!为随意字符)
$ sed 's!/!aa/' afile
## sed -e 多个命令的使用
$ sed  -e 's/a/aa/'  -e 's/aa/bb/' afile
## 等同于上面的效果 
$ sed   's/a/aa/;s/aa/bb/' afile

## 执行多个文件
$ sed  's/a/aa/;s/aa/bb/' afile bfile cfile
## 将修改的内容写回到源文件
$ sed  -i 's/a/aa/;s/aa/bb/' afile bfile cfile
## 将修改的内容重定向写入到bfile中
$  sed  's/a/aa/;s/aa/bb/' afile > bfile

## 将/home/a.txt文件的前5行中第一个三个字符替换为空 
$ head -5 /home/a.txt | sed 's/...//'
## 将 grep root /etc/passwd 查询出的带root的字符中 以root为开始的字符替换为空
$ grep root /etc/passwd  | sed 's/^root//'

## (*为正则语法 表示配置*号前面的b字符出现0次或者多次)
$ sed 's/ab*/!/' bfile

## (+号表示匹配一次或者多次)
$ sed  -r 's/ab+/!/' bfile
## (?号表示匹配0次或者1次)
$ sed  -r 's/ab?/!/' bfile
## (a|b  表示匹配a或者b)
$ sed  -r 's/a|b/!/' bfile
## ((aa)|(bb)  表示匹配aa或者bb  多个字符要用括号括起来)
$ sed  -r 's/(aa)|(bb)/!/' bfile

$ echo axyzb > cfile
## sed 中()的另外一个作用是 回调(\1 反斜杠1表示前面第一个括号的回调)
$ sed -r 's/(a.*b)/\1:\1' cfile
# 结果: axyzb:axyzb 

在这里插入图片描述
在这里插入图片描述

进阶使用

全局替换

s/old/new/g g为全局替换,用于替换所有出现的次数
s/old/new/n (n为数字 表示出现第几次是进行替换) 配置第n次 进行替换
/如果和正则匹配的内容冲突可以使用其他符号,如: s@old@new@g 、s!old!new!g

标志位

s/old/new/标志位
标志位可以为如下:
数字,第几次出现才进行替换
g,每次出现都进行替换
p打印模式空间的内容。适霜
sed -n ‘script’ filename阻止默认输出
w file将模式空间的内容写入到文件

## 组织默认输出,只输出匹配到的内容
$ head -5 /etc/passwd | sed -n 's/root/!!!!/p' 
## 将输出的结果写入到/tmp/a.txt文件中
$ head -5 /etc/passwd | sed -n 's/root/!!!!/w   /tmp/a.txt' 

默认对每行进行操作,增加寻址后对匹配的行进行操作
/正则表达式/s/old/new/g
行号s/old/new/g
行号可以是具体的行,也可以是最后一行$符号
可以使用两个寻址符号,也可以混合使用行号和正则地址

## 只匹配第一行
$ head -6 /etc/passwd | sed '1s/adm/!/
## 匹配第一行到第三行
$ head -6 /etc/passwd | sed '1,3s/adm/!/
## 匹配第一行到最后一行
$ head -6 /etc/passwd | sed '1,$s/adm/!/
## 只匹配root所在的行
$ head -6 /etc/passwd | sed '/root/s/adm/!/
## 只匹配以bin开头的行
$  head -6 /etc/passwd | sed '/^bin/s/adm/!/
## 只匹配以bin开头的行
$  head -6 /etc/passwd | sed '/^bin/,$s/adm/!/

可以将选项保存为文件,使用-f加载脚本文件
sed -f sedscript filename

分组:

寻址可以匹配多条命令
/regular/{s/old/new/;s/old/new/}

sed 脚本文件

可以将选项保存为文件,使用-f加载脚本文件
sed -f sedscript filename

sed 其他命令

删除命令

[寻址] d 删除模式空间内容,改变脚本的控制流,读取新的输入行
d后的任何指令都不会被执行

追加、插入、更改

追加命令 a
插入命令 i
更改命令 c

读、写

读文件命令 r
写文件命令 w

下一行

下一行命令 n
打印行号命令 =

打印

打印命令 p

退出命令

退出命令 q

## 匹配ab 并在找到的行的前一行添加hello
$ sed '/ab/i hello' bfile
## 匹配ab 并在找到的行的上一行添加hello
$  sed '/ab/a hello' bfile
## 匹配ab 并将找到的行更改为hello
$  sed '/ab/c hello' bfile

##  匹配ab 并将找到的行替换为从afile中读取到内容填充这一行
$ sed '/ab/r afile' bfile
##  将修改的内容保存到gfle 中
$ sed '/ab/r afile' bfile > gfile


## 匹配ab  匹配到后再输出一次
$ sed '/ab/p' bfile
## 只输出匹配的行
$ sed -n '/ab/p' bfile

## 产生1-10000000 的数字每行一个
$ seq 1 10000000 > lines.txt 
## 读写1-10行并打印  (次命令将1-10行读取到内存后,继续将11-结尾行读取到内存)
$ time sed -n '1,10p' lines.txt 
## 读写1-10行打印并退出 (次命令效率很高) (次命令只讲1-10行读取到内存)
$ time sed -n '10q' lines.txt

sed 多行模式

N将下一行加入到模式空间
D删除模式空间中的第一个字符到第一个换行符
P打印模式空间中的第一个字符到第一个换行符

创建一个1.txt的文件

hel
lo
## 此命令不会匹配到任何内容 (因为文本存储是 会有换行符 \n)
$  sed 'N;s/hello/!!!/' 1.txt
## 匹配到hello
$  sed 'N;s/hel\nlo/!!!/' 1.txt
## 多行模式中可以使用.替换\n
$ sed 'N;s/hel.lo/!!!/' 1.txt
## 创建一个b.txt的文件
$ cat > b.txtx << EOF
> hello
> o bash hel
> lo bash
> EOF
## 每两行 作为输出
$ sed 'N;s/\n//;s/hello bash/hello sed\n/;P;D'  b.txt
## 每三行 作为输出
$ sed 'N;N;s/\n//;s/hello bash/hello sed\n/;P;D'   b.txt

sed 保持空间

h和H将模式空间内容存放到保持空间 (小写h为覆盖 ,大写H为追加)
g和G将保持空间内容取出到模式空间 (小写g为覆盖 ,大写G为追加)
x交换模式空间和保持空间内容
在这里插入图片描述

awk

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
(相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题)
(通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本)

语法:awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
[-F|-f|-v] 大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
’ ’ 引用代码块
BEGIN 初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
// 匹配代码块,可以是字符串或正则表达式
{} 命令代码块,包含一条或多条命令
; 多条命令使用分号分隔
END 结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息

输入数据前例程BEGIN{} ## BEGIN 的操作在读取文件之前
主输入循环{}
所有文件读取完成例程 END{}

每行称作AWK的记录
使用空格、制表符分隔开的单词称作字段
可以自己指定分隔的字段

字段的引用

默认情况下,awk 会将如下变量分配给它在文本行中发现的数据字段:
$0 代表整个文本行;
$1 代表文本行中的第 1 个数据字段;
$2 代表文本行中的第 2 个数据字段;
$n 代表文本行中的第 n 个数据字段。

## 输出 以menu开头的行 
$ awk '/^menu/{ print $0 }' /boot/grub2/grub.cfg
## 输出 以menu开头的行并按照空格分行 展示分隔后的第二个数据 
$ awk  -F "'" '/^menu/{ print $2 }'   /boot/grub2/grub.cfg
## 输出 以menu开头的行并按照空格分行 展示分隔后的第二个数据 并在前面添加序号
$ awk  -F "'" '/^menu/{ print x++; $2 }'   /boot/grub2/grub.cfg

赋值操作符

=是最常用的赋值操作符

var1="name"
var2="hello""world"
var3=$1

其他复制操作符

++ – += -= *= /= %= ^=

算数操作符

      • / % ……

系统变量

FS和OFS字段分隔符,OFS表示输出的字段分隔符, RS记录分隔符
NR和FNR行数
NF字段数量,最后一个字段内容可以用$NF取出

##
$ head -5 /etc/passwd  | awk  'BEGIN{FS=":"}{print $1}'
## 等同于上面的效果
$  head -5 /etc/passwd  | awk -F ":" '{print $1}'

## 输出 以:分隔的第一个字符和第二个字符
$ head -5 /etc/passwd  | awk  'BEGIN{FS=":"}{print $1,$2}'
## 输出 以:分隔的第一个字符和第二个字符 并使用-将字符连接
$ head -5 /etc/passwd  | awk  'BEGIN{FS=":";OFS="-"}{print $1,$2}'

## 以:作为行的分隔符输出内容
$  head -5 /etc/passwd  | awk  'BEGIN{RS=":"}{print $0}'
## 显示行号(NR)和内容($0)
$  head -5 /etc/passwd  | awk  '{print NR,$0}'

## 显示多个文件的行号和内容 (FNR 行号会重置)行号会在第二个文件输出时重置(重新重1开始)
$ awk '{print FNR,$0}' /etc/hosts  /etc/hosts
## 显示多个文件的行号和内容  NR行号连续
$ awk '{print NR,$0}' /etc/hosts  /etc/hosts
## 以:为分隔符统计每行的数量
$ head -5 /etc/passwd  | awk 'BEGIN{FS=":"}{print NF}' 

条件语句

if判断:
条件语句使用if开头,根据表达式的结果来判断执行哪条语句
if(表达式)
awk语句1
[else
awk语句2
]
如果有多个语句需要执行可以使用{}将多个语句括起来

while循环:
while(表达式)
awk语句1

do循环:
do{
awk 语句①
}while(表达式)

for循环:
for(初始值;循环判断条件;累加)
awk语句1
影响控制的其他语句:
break
continue
在这里插入图片描述

##
$ awk '{if($2>=80) print $1}'  kpi.txt
##
$ awk '{if($2>=80) {print $1 ; print $2} }'  kpi.txt


## NF 表数字数量的最大值  输出 
$ head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) print $c} '
# 结果:
#	70
#	72
#	74
#	76
#	74
#	72 
## 输出第一行的总和
$ head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) sum+=$c; print sum} '
## 输出第一行的平均值
$ head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) sum+=$c; print sum/(NF-1)} '
## 输出每一行的平均值
$ awk '{sum=0;for(c=2;c<=NF;c++) sum+=$c; print sum/(NF-1)} '

制作加载awk脚本

制作: 将awk命令复制到.awk文件中
加载: awk -f avage.awk kpi.txt

awk数组

数组的定义: 数组名[下标] =值
数组的遍历: for(变量 in 数组名) 使用数组名[变量]的方式依次对每个数组进行操作
删除数组: delete 数组[下标]
命令行参数数组

## 输出每一行的平均值 average[$1] 表示每行用户的名称
[ root@ server ~]#  awk '{ sum=0; for(column=2; column<=NF; column++) sum+=$column; average[$1]=sum/(NF-1)} END {for(user in average) print user, average[ user]}'
## 输出所有的平均值
[ root@ server ~]#  awk '{ sum=0; for(column=2; column<=NF; column++) sum+=$column; average[$1]=sum/(NF-1)} END {for(user in average) sum2+=average[ user] ;print sum2/NR }'

命令行参数数组

ARGC awk 命令后面所带参数的个数 (ARGC 命令行参数的数目)
ARGV awk 命令后面所带参数具体每个参数的内容 (包含命令行参数的数组)

创建arg.awk文件

BEGIN{
	for(x=0;X<ARGC;x++)
		print ARGV[x]
	print ARGC
}

执行arg.awk文件

##
$ awk -f arg.awk  11  22 33 
# 结果:
#  awk  (ARGV[0]  命令的名称)
#  11
#  22
#  33 
#  4   (ARGC 命令的个数)

awk 数组功能的使用

创建 result.awk

{
sum=0
for(column=2;column <=NF;column++)
	sum+=$column 
average[$1]=sum/(NF-1)
print $1,average[$1]

if(average[$1]>=80)
	letter ="S"
else if( average[$1]>=70)
	letter ="A"
else if( average[$1]>=60)
	Letter ="B"
else 
	letter="C"
print $1,average[$1],letter

letter_all[letter]++
}
END{
for( user in average)
	sum_all +=average[user]
avg_all=sum_all /NR
print "average all:", avg._all 
for( user in average)
	if( average[user]>avg_all)
		above++
	else 
		below++

print "abovel",above 
print "below",below
print "s:",letter_alL["S"]
print "A:",letter_alL["A"]
print "B:",letter_alL["B"]
print "c:",Letter_alL["C"]

执行 result.awk

$ awk -f result.awk kpi.txt

结果:
在这里插入图片描述

awk 函数

rand() 随机数
srand() 重新获取种子
gsub(r,s,t)
index(s,t) 从字符串中取值
length(s) 字符串长度
match(s,r) 字符串匹配
split(s,a,sep) 字符串分隔
sub(r,s,t)
substr(s,p,n)

## 输出随机数 (不重复的随机数)
$ awk 'BEGIN{srand();print rand()}'
##  awk 'BEGIN{print rand()}' 输出的随机数是重复的  
$ awk 'BEGIN{print rand()}'

自定义函数

function 函数名(参数){
	awk语句
	return awk变量
}

参考:

linux awk命令详解
linux中的awk命令详解
linux命令大全 awk命令

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值