赞
踩
10.193.183.131
改成10-193-183-131
s
表示替换指定字符,g
表示全面替换,类似Java String类的replaceAll,否则默认替换第一个匹配的字符"s/source-string/target-string/g"
,表示使用 target-string 将匹配行中所有source-stringhostname -i | sed "s/\./-/g"
删除匹配行,末尾使用d
选项
# 删除包含sunrise的行
echo "hello, lucy
hello, sunrise" | sed "/sunrise/d"
# 执行结果
hello, lucy
通过-i
选项基于文件进行修改,如果怕直接修改出问题,可以 -iSUFFIX
创建备份文件,SUFFIX
是自定义的后缀名
# 文件内容
hello, world
sunrise lucy
10.193.24.145
# 以备份文件的形式进行修改
sed -i_bak_20220120 "s/\./-/g" test
# 将创建test_bak_20220120备份文件,test内容修改如下
hello, world
sunrise lucy
10-193-24-145
向文件中插入多行,通过\n
实现
sed -i "s/hello, world/hello, jack\nhello, grace/g" test
# 修改后的内容
hello, jack
hello, grace
sunrise lucy
10-193-24-145
-r
正则匹配,如删除以hello
开头的行
sed -ri "/^hello.*/d" test
# 经过实践,不加r也是可以的
sed -i "/^hello.*/d" test
# 修改后的内容
sunrise lucy
10-193-24-145
例如,正则匹配,删除多余的空格
echo " hello| hadoop | test" | awk -F '|' '{print $2}' | sed -r 's/( )+//g'
其余可以参考:sed命令
target-string
部分,使用变量ip=`hostname -i |sed 's/\./-/g'`
node_id="node.id=coordinator-"${ip}
sed -ri "s/^node.id.*/${node_id}/g" $HOME/node.properties
删除指定字符,如最后1个、开始的3个,使用.
表示匹配一个任意字符,;
实现多个操作指令的拼接。更多操作,见博客:使用 sed 命令替换/删除 文本字符的 20 个例子
# 删除最后一个字符
echo "250G" | sed -r "s/.{1}$//"
# 删除前3个字符
echo "123hello" | sed -r "s/...//"
# 删除最后一个x
echo "hellox" | sed -r "s/x$//"
# 同时删除前3个和最后一个字符
echo "123hellox" | sed -r "s/...//;s/x$//"
awk中,使用RS
(记录分割符)分割出的一条数据,叫做一条记录,Record。
awk命令的重点,就是使用FS
(字段分割符)对一条Record进行分割,得到若干字段,Field
默认的RS
是换行符\n
,默认的FS
是空格
(连续的若干空格)
test文件记录的是员工的工资条信息,其内容如下:
100 Thomas Manager Sales $5000
200 Jason Developer Technology $5500
300 Sanjay Sysadmin Technology $7000
400 Nisha Manager Marketing $9500
500 Randy DBA Technology $6000
通过awk命令的默认分割符进行分割后,100 Thomas Manager Sales $5000
就是一条Record,100
、Thomas
、Manager
等就是Field
awk命令的完整结构如下
awk 'BEGIN{action1; action2; ...;}
{action1; action2; ...;}
END{action1; action2; ...;}'
其中,BEGIN
用于定义对每条记录进行处理前的一些初始化工作,例如,定义变量、设置分割符等
END
用于定义处理完所有记录后的一些收尾工作,例如,打印处理的记录总数,最大值、最小值等
BEGIN
和END
动作块中间的动作块,则表示对每条记录进行的操作(自己喜欢称其为record action part
)
一个完整的awk命令示例如下:
# 整体结构为
begin action part [可选]
record action part [必须]
end action part [可选]
按照awk命令的完整结构,对test文件进行处理,实现工资条的打印并统计员工数
# FS:指令
awk 'BEGIN{FS="$"}
{print $NF}
END{print "员工数:", NR}' test
执行结果如下:
注意事项
BEGIN
和END
后面必须跟着使用{action1; action2; ...}
表示的动作块(action part),不允许换行;如果换行,命令执行会报错!!
例如,下面的命令将会执行报错,提示BEGIN blocks must have an action part
。
awk 'BEGIN
{FS="$";}
{print $1, $2}' test
使用awk进行分割并打印所有列,等价于cat命令。其中,$0
表示整条记录
# 不指定具体的列,默认print所有列
awk '{print;}' test
# 或者,省略最后一个action的;
awk '{print}' test
# 或者,显式指定打印整条记录
awk '{print $0}' test
执行结果:
使用awk进行分割并打印指定列
其中,$N
表示第N列,$0
表示整条记录;NF
是记录中的字段(列)数,$NF
则表示最后一列的值
# 打印第二列和最后一列
awk '{print $2, $5}' test
# 或者
awk '{print $2, $NF}' test
执行结果:
除了NF
,还有一个内置变量NR
,用于表示处理过的记录条数,是一个不断变化的值,相当于每条记录的编号。
当处理完最后一条记录时,NR对应的就是记录的总条数
# 为每条记录加上行号
awk '{print NR, $0} END{print "共有", NR, "条薪资记录"}' test
-F
或FS,指定Field分割符awk默认分割符为空格,可以通过-F
指定分割符
# 以$作为分隔符,产生2列数据
awk -F '$' '{print $1, $2}' test
执行结果
-F
对应awk的内建变量FS
,上面的命令可以书写如下
awk 'BEGIN{FS="$";} {print $1, $2}' test
通过以上命令的执行,我们不难发现:通过print
打印每列时,依然使用空格作为分隔符
有时,我们需要使用其他的分隔符。这时,可以使用awk的内建变量OFS
指定打印时的分隔符
以|
作为列分割符
awk 'BEGIN{OFS=" | "} {print $1, $2, $NF}' test
打印效果如下:
tmp_file文件内容如下,---------------
是Record分割符,如果再使用默认的\n
做分割则不再适用
100 Thomas Manager Sales $5000
---------------
200 Jason Developer Technology $5500
这时候,可以使用RS
指定分隔符,对文本进行分割
awk 'BEGIN{RS="---------------\\n"} {print $0}' tmp_file
笔者有一个需求:通过print打印的各字段之间无任何分隔符(看起来就是分隔符为空字符串''
)
使用如下命令成功打印:
awk 'BEGIN{OFS=""} {print $2,$NF}' test
需求进阶:员工姓名长度不一致,希望左对齐,占据相同宽度,然后再打印员工薪水,类似编程语言中的printf("%-20s%s", $1, $NF)
通过查阅资料,发现awk也提供了printf
操作,用于格式化打印
上述需求,对应的awk命令:
awk '{printf "%-8s%s\n", $2, $NF}' test # 注意需要手动换行
执行结果如下:
关于printf
更多的信息,可以查阅下面的资料
,
去除避免影响计算实战:求员工薪水的和
# sum+=$NF,定义sum变量,并对薪资列进行累加求和
awk -F '$' '{sum+=$NF} END {print "员工薪水总和:", sum}' test
执行结果:
求平均值,print时,使用sum / NR
即可
实战:求员工薪水的平均值
awk -F '$' '{sum+=$NF} END {print "员工平均工资:", sum/NR}' test
执行结果
实战:计算最高薪资
awk -F '$' 'BEGIN {max_salary=0}
{if($NF > max_salary) max_salary=$NF}
END { print "最高薪资:", max_salary}' test
# 简写如下
awk -F '$' '{if($NF > max_salary) max_salary=$NF}
END { print "最高薪资:", max_salary}' test
# 等价于if语句
awk -F '$' '$NF > max_salary {max_salary=$NF; max_record=$0 };
END { print "最高薪资:", max_salary, "\n完整记录 --", max_record}' test
执行结果1:
执行结果2:
执行结果3:
# not working的写法
awk -F '$' '$NF < min_salary {min_salary=$NF;}; END { print "最低薪资:", min_salary}' test
# 设置一个合理的初始值
awk -F '$' 'BEGIN {min_salary=10000000} {if($NF < min_salary) min_salary=$NF} END { print "最低薪资:", min_salary}' test
# 最智能的做法,将第一条记录的值作为初始值
awk -F '$' '{
if(NR == 1)
{line = $0; min = $NF;}
else if(NR > 1 && $NF < min)
{line = $0; min = $NF;}
}
END {print min,"--",line}' test
具体可以参考文档:4 Awk If Statement Examples ( if, if else, if else if, :? )
一般的语法如下:
if(conditional-expression1)
action1;
else
action2;
其中,action可以是使用{}
包裹的多个action的组合
{
action1;
action2;
}
自己的示例
cat $file | grep "Full GC" -A 2 \
| awk 'BEGIN{max=0;OFS="";target="2022-06-15T00:00:00"}
{if($1>max) max=$1}
END{if(max>0) {print "晚于",target,"的最长full gc时间: ",max,"秒"}
else {print "不存在晚于",target,"的full gc"}}'
自己的文件内容如下, --\n
(\n
是隐形的)是一条完整的record的分隔符,\n
是每个field的分隔符
2022-06-06T10:49:18.858+0800: 52336.450: [Full GC (Allocation Failure) 177G->121G(180G), 153.0179210 secs] [Eden: 0.0B(9216.0M)->0.0B(9216.0M) Survivors: 0.0B->0.0B Heap: 177.0G(180.0G)->121.1G(180.0G)], [Metaspace: 153392K->151568K(178176K)] [Times: user=216.81 sys=5.56, real=153.02 secs] -- 2022-06-06T10:52:21.935+0800: 52519.526: [Full GC (Allocation Failure) 177G->95G(180G), 108.4246053 secs] [Eden: 0.0B(9216.0M)->0.0B(9216.0M) Survivors: 0.0B->0.0B Heap: 177.9G(180.0G)->95.1G(180.0G)], [Metaspace: 151861K->151604K(178176K)] [Times: user=162.21 sys=0.53, real=108.42 secs] -- 2022-06-06T13:44:04.202+0800: 62821.794: [Full GC (Allocation Failure) 177G->114G(180G), 145.3675436 secs] [Eden: 0.0B(9216.0M)->0.0B(9216.0M) Survivors: 0.0B->0.0B Heap: 178.0G(180.0G)->114.2G(180.0G)], [Metaspace: 152892K->152677K(180224K)] [Times: user=206.21 sys=3.66, real=145.36 secs] -- 2022-06-06T13:46:59.241+0800: 62996.833: [Full GC (Allocation Failure) 178G->70G(180G), 88.3189255 secs] [Eden: 0.0B(9216.0M)->0.0B(9216.0M) Survivors: 0.0B->0.0B Heap: 178.3G(180.0G)->70.7G(180.0G)], [Metaspace: 152700K->152663K(180224K)] [Times: user=129.14 sys=0.74, real=88.32 secs] -- 2022-06-06T14:45:15.222+0800: 66492.813: [Full GC (Allocation Failure) 179G->22G(180G), 43.2909254 secs] [Eden: 0.0B(9216.0M)->0.0B(9216.0M) Survivors: 0.0B->0.0B Heap: 179.1G(180.0G)->22.1G(180.0G)], [Metaspace: 154384K->152752K(180224K)] [Times: user=55.39 sys=0.69, real=43.29 secs]
我有个需求,需要获取每次full gc的时间,也就是每条record最后一个field中的real=43.29 secs
而awk默认的record分隔符为\n
、field分隔符为空格
,这时就需要自定义分隔符了
# RS用于指定record的分隔符,FS用于指定field的分隔符
cat test | awk 'BEGIN{RS="--\\n";FS="\\n"} { print $3}' \
| awk -F "real=" '{print $2}' | awk '{print $1}'
最终的执行结果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。