sed 以及 awk用法
sed 格式
sed[options] "script" FILE....
选项:
-n:静默模式,不输出模式空间内的内容;默认打印空间模式的内容
-r:扩展的正则表达式
-f 文件:指定sed脚本文件
-e 'script' -e 'script' :指定多个编辑指令
-i : 直接编辑原文件
编辑命令:
d:删除
p: 打印
i \text:在被指定到的行前面插入文本
a \text:在被指定的行的下面插入文本
\n:换行
r /path/file.txt:在指定位置把另外一个文件的内容插入
w /path/file.txt:将符合条件的所有行保存至指定文件中
=:显示符号条件的行的行号
s///:查找条件可以使用模式,但是要替换的内容不行
sed '地址定界s@查找条件@替换文件@'
修饰符:
g:global,全局替换
i:ignore-case,不区分字符大小写
地址定界:自定义的起始行到结束行
startline,endline
1,3
/pat1/,/pat2/
/pattern/
用法:sed [options] 'addr1[,addr2]编辑命令' FILE...
sed [options] "addr1[,addr2]编辑命令" FILE...
用法
1. 删除 /etc/puppet/puppet.conf 1到13行的数据 [root@k8s1 ~]# sed '1,13d' /etc/puppet/puppet.conf
2. 删除以空格或者tab的集合开头的行
[root@k8s1 ~]# sed '/^[[:space:]]/d' /etc/puppet/puppet.conf
3.删除空行
[root@k8s1 ~]# sed '/^[[:space:]]*$/d' /etc/puppet/puppet.conf
4.删除fstab中以/ 开头的行。
[root@k8s1 ~]# sed '/^\//d' /etc/fstab
5.删除第2行到第一次出现 / 的行,结束是在/ 行后
[root@k8s1 ~]# sed '2,/^\//d' /etc/fstab
6.删除以 # 开始到第一次出现 / 的行,结束是在/ 行后
[root@k8s1 ~]# sed '/^#/,/^\//d' /etc/fstab
7.显示打印以 # 开始到第一次出现 / 的行,结束是在/ 行后
[root@k8s1 ~]# sed -n '/^#/,/^\//p' /etc/fstab
8.在空行前添加 11111111111111
[root@k8s1 ~]# sed '/^$/i \111111' /etc/fstab
[root@k8s1 ~]# sed '/^[[:space:]]*$/i \111111' /etc/fstab
9.在空行后添加 11111111111111
[root@k8s1 ~]# sed '/^$/a \111111' /etc/fstab
[root@k8s1 ~]# sed '/^[[:space:]]*$/a \111111' /etc/fstab
10.在大写字母后添加2行
[root@k8s1 ~]# sed '/^[[:upper:]]/a \aaaaaaaaaaa\nbbbbbbbbb' /etc/issue
11. 在一个大写字母行后,把另一个文件内容追加进来。
[root@k8s1 ~]# sed '/sda2/r /etc/issue' /etc/fstab
12. 将fstab 中包含 / 的保存在/tmp/file.txt中
sed '/\//w /tmp/file.txt' /etc/fstab
13.显示匹配的行号
[root@k8s1 ~]# sed '/\//=' /etc/fstab
14. 把 /etc/issue内容 添加到fstab 第2行后
[root@k8s1 ~]# sed '2r /etc/issue' /etc/fstab
list.txt 文件内容如下:
docker:x:996:993:Docker User:/var/lib/docker:/sbin/nologin
etcd:x:995:992:etcd user:/var/lib/etcd:/sbin/nologin
puppet:x:52:52:Puppet:/var/lib/puppet:/sbin/nologin
centos:x:2000:2000::/home/centos:/bin/bash
nginx:x:990:9909:Nginx web server:/var/lib/nginx:/sbin/nologin
15.删除一行中出现相同docker的行
[root@k8s1 ~]# sed '/\(d.*r\).*\1/d' list
16.删除一行中出现相同字符的行
[root@k8s1 ~]# sed '/\(*.\).*\1/d' list
17.替换第二个docker为Docker
[root@k8s1 ~]# sed '/\(d.*r\).*\1/s@dockeri@Dockeri@' list
18.替换 /etc/inittab 中 id:3:initdefault 变成数字5
[root@python tmp]# sed '/id:/s@[0-9]@5@' /etc/inittab
19.替换/etc/inittab 中 以#开头和后面有空格的行
[root@python tmp]# sed '/^#/s@^#[[:space:]]\{0,1\}@@g' inittab
20.删除/etc/inittab 中所有开头是空白的行
sed 's@^[[:space:]]\{1,\}@@g' /etc/inittab
awk命令:
awk:报告生成工具
把文件中读取带的每一行的每个字段分别进行格式化,而后进行显示:
支持使用变量、条件判断、循环、数组
选项:
-F:切割符
$0:整行
$1,$2.....:位置参数
用法格式:
awk [options] 'script' FILE...
awk [options] '/pattern/{action}' FILE...
action: print $1,$2
[root@k8s1 ~]# awk -F":" '{print $1}' /etc/passwd
模式:
地址定界:/pat1/,/pat2/ 一个范围
/pattern/ 被匹配到的行
experssion 表达式 $3 > 2000
>,>=,<,<=,==,!=,~(模式匹配)
BEGIN:在遍历操作开始之前执行一次: awk 'BEGIN{print "name"}{print $1,$2}'
END:在遍历操作结束之后,命令退出之前退出一次。 awk 'BEGIN{print "name"}{print $1,$2}END{print “----------”}'
awk的常用四种分隔符:
输入:
行分隔符
字段分隔符
输出:
行分隔符
字段分隔符
awk内置变量之数据变量:
NR: The number of input records,awk命令所处理的记录数;如果有多个文件,这个数目会把处理的多个文件中行统一计数;
NF:Number of Field,当前记录的field个数;
FNR: 与NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数;
ARGV: 数组,保存命令行本身这个字符串,如awk '{print $0}' a.txt b.txt这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt;
ARGC: awk命令的参数的个数;
FILENAME: awk命令所处理的文件的名称;在命令中获取当前文件名
ENVIRON:当前shell环境变量及其值的关联数组;
[root@k8s1 ~]# awk -F":" '/centos/{print $0}' /etc/passwd
centos:x:2000:2000::/home/centos:/bin/bash
[root@k8s1 ~]# awk -F":" '/12/{print $0}' /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
[root@k8s1 ~]# awk -F":" '$3>2000 {print $0}' /etc/passwd
suse:x:3000:3000::/home/suse:/bin/bash
[root@k8s1 ~]# awk 'BEGIN{print "name:-------"}{print $1} END{print "-----------------"}' /etc/passwd
name:-------
......
----------
显示最后一列
[root@k8s1 ~]# awk -F":" '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
输入按照:号切割,输出按照+号显示
[root@k8s1 ~]# awk 'BEGIN{FS=":";OFS="+"}{print $1,$7}' /etc/passwd
root+/bin/bash
使用NR 显示总行数
[root@k8s1 ~]# awk '{print NR,$0}' /etc/passwd /etc/fstab
使用FNR 对每个文件计数
[root@k8s1 ~]# awk '{print FNR,$0}' /etc/passwd /etc/fstab
ARGV[0] 等于awk,ARGV[1]等于/etc/passwd,但是会循环显示 /etc/passwd
[root@k8s1 ~]# awk -F ":" '{print ARGV[0]}' /etc/passwd
可以使用BEGIN,在循环前执行
[root@k8s1 ~]# awk 'BEGIN{print ARGV[0]}'
[root@k8s1 ~]# awk -F":" '{print $1“ is a user in ”ARGV[1]}' /etc/passwd
FILENAME: awk命令所处理的文件的名称;在命令中获取当前文件名
[root@k8s1 ~]# awk '{print $0" in "FILENAME}' /etc/passwd
使用-v 自定义变量,或者直接在BEGIN中定义
[root@k8s1 ~]# awk -v num1=30 -v num2=30 'BEGIN{print num1+num2}'
[root@k8s1 ~]# awk 'BEGIN{num1=20;num2=30; print num1+num2}'
条件表达式 if
print 的区别,一个对整个行操作,一个在操作行之前操作
[root@k8s1 ~]# awk 'BEGIN{num1=231;num2=500;num1>num2?max=num1:max=num2;print max}'
500
[root@k8s1 ~]# awk 'BEGIN{num1=30;num2=55;num1>num2?max=num1:max=num2} {print max}' /etc/passwd
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516104846775-1203862445.png)
printf
printf命令的使用格式:
printf format, item1, item2, ...
要点:
1、其与print命令的最大不同是,printf需要指定format;
2、format用于指定后面的每个item的输出格式;
3、printf语句不会自动打印换行符;\n
format格式的指示符都以%开头,后跟一个字符;如下:
%c: 显示字符的ASCII码;
%d, %i:十进制整数;
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身;
修饰符:
N: 显示宽度;
-: 左对齐;
+:显示数值符号;
例子:
[root@k8s1 ~]# awk -F":" '{printf "%-20s %s\n",$1,$NF}' /etc/passwd
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516105509244-1387649114.png)
[root@k8s1 ~]# awk 'BEGIN{sum=55;printf "%d\n",sum}'
55
常见的模式类型:
1、Regexp: 正则表达式,格式为/regular expression/
2、expresssion: 表达式,其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 == "magedu",用运算符~(匹配)和!~(不匹配)。
3、Ranges: 指定的匹配范围,格式为pat1,pat2
4、BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次
5、Empty(空模式):匹配任意输入行;
/正则表达式/:使用通配符的扩展集。
关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。
模式匹配表达式:
模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
END:让用户在最后一条输入记录被读取之后发生的动作。
控制语句:
1 if-else
语法:awk '{if (condition) {then-body} else {[ else-body ]}}'
#
[root@k8s1 ~]# awk '{if ($3==0) {print $1, "Adminitrator";} else { print $1,"Common User"}}' /etc/passwd
[root@k8s1 ~]# awk -F":" '{if ($3==0) {printf "%-18s $s\n",$1,"is administrator"} else {printf "%-18s %s\n",$1,"is comm user"}}' /etc/passwd
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516115653869-1694109378.png)
统计匹配的行,sum++ 就是循环一次,自身加1
[root@k8s1 ~]# awk -F: -v sum=0 '{if ($3>500) {sum++}} END{print sum}' /etc/passwd
[root@k8s1 ~]# awk -F":" 'BEGIN{sum=0} {if($4="192.168.2.1") {sum++}} END{print sum}' fengjian
while
语法:awk '{i=1; while (i<5) {print $i;i++}}' file
[root@k8s1 ~]# awk -F":" '{i=1; while(i<NF) {printf "%s:",$i;i++} ;printf "\n"}' /etc/passwd
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516155014807-649897235.png)
[root@k8s1 ~]# awk -F":" '{i=1; while(i<NF) {if($i==3000) {print $i};i++}}' /etc/passwd
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516155824432-545284654.png)
for
语法: for ( variable assignment; condition; iteration process) { statement1, statement2, ...}
[root@k8s1 ~]# awk -F":" '{for(i=1;i<=NF;i++){printf "%s:",$i};printf "\n"}' /etc/passwd
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516160254775-867835599.png)
[root@k8s1 ~]# awk -F":" '{for(i=1;i<=NF;i+=2){printf "%s:",$i};printf "\n"}' /etc/passwd
for循环还可以用来遍历数组元素:
语法: for (i in array) {statement1, statement2, ...}
awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}' /etc/passwd
array[index-expression]
index-expression可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用index in array的方式。
要遍历数组中的每一个元素,需要使用如下的特殊结构:
for (var in array) { statement1, ... }
其中,var用于引用数组下标,而不是元素值;
例子:
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引;
awk '{counts[$1]++}; END {for(url in counts) print counts[url], url}' /var/log/httpd/access_log
用法与上一个例子相同,用于统计某日志文件中IP地的访问量
从关系数组中删除数组索引需要使用delete命令。使用格式为:
delete array[index]
[root@haproxy1 ~]# netstat -an | awk '/^tcp/{state[$NF]++} END{for(A in state) {print A,state[A]}}'
统计非空白行访问IP的数量
[root@tracker1 logs]# awk '!/^!/{ACCESS[$1]++} END{for(a in ACCESS) {print a,ACCESS[a]}}' access.log
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516180829150-2078200636.png)
统计访问的路径
[root@S1PW003 logs]# awk '/GET/{res[$7]++} END{for(i in res) {print i,res[i]}}' access.log
![](https://images2015.cnblogs.com/blog/886010/201705/886010-20170516181434322-1449488924.png)
统计varnish状态码
[root@haproxy1 logs]# awk '/varnish/{code[$11]++} END{for(i in code) {print i,code[i]}}' haproxy_http.log
显示为基数的行/etc/passwd,使用next
[root@k8s1 ~]# awk -F":" '{if($3%2==0) {next} else {print $1,$3}}' /etc/passwd
统计当前系统上每个客户端IP的连接中处于TIME_WAIT的连接状态的个数;
[root@xinyixy_pc_006 ~]# netstat -an | awk '/TIME_WAIT/{laststr[$NF]++} END{for(i in laststr) {print i,laststr[i]}}'
统计ps aux命令执行时,当前系统上各用户的进程的个数;
root@xinyixy_pc_006 ~]# ps aux | awk '{state[$8]++}END{for(i in state) {printf "%-15s %s\n",i,state[i]}}'
awk的内置函数
awk '{split(分割的字段, 数组名称 ,分割符)'}
功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从1开始的序列;
# netstat -ant | awk '/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50
# netstat -tan | awk '/:80\>/{split($5,clients,":");ip[clients[4]]++}END{for(a in ip) print ip[a],a}' | sort -rn | head -50
# df -lh | awk '!/^File/{split($5,percent,"%");if(percent[1]>=20){print $1}}'
[root@xinyixy_ha_001 ~]# netstat -anpt | awk '{split($7,program,"/");res[program[2]]++} END{for(i in res) {print res[i],i}}'
length([string])
功能:返回string字符串中字符的个数;
substr(string, start [, length])
功能:取string字符串中的子串,从start开始,取length个;start从1开始计数;
system(command)
功能:执行系统command并将结果返回至awk命令
systime()
功能:取系统当前时间
tolower(s)
功能:将s中的所有字母转为小写
toupper(s)
功能:将s中的所有字母转为大写