awk、sed
一、sed相关
1、在sed中引入shell变量的方法
eval sed 's/$a/$b/' filename sed "s/$a/$b/" filename sed 's/'$a'/'$b'/' filename sed s/$a/$b/ filename
2、sed中使用正则表达式进行替换的时候,一定要注意有些特殊字符在使用时要转义
需要转义的特殊字符:
用于分组的小括号:( ),在使用时要用\进行转义,但是匹配字符串中真正的小括号时,无需转义
表示前面的表达式出现次数的{},也要转义
表示前面的表达式出现1次或多次的+,也要转义,在使用时,要用\+
表示前面的表达式至多出现1次?,也要转义,在使用时,要用\?
不需要转义的特殊字符:
用于表示字符集的[ ]
表示前面的表达式出现0次或多次的*
有些特殊字符在sed的正则表达式中不能用,比如要表示匹配一个数字不能用\d,而要用[0-9]
例:
sed -i 's#grafana:[0-9]\+.[0-9]\+.[0-9]\+-[0-9]\+$#grafana:latest#g' grafana.yaml sed -ri 's#grafana:[0-9]+.[0-9]+.[0-9]+-[0-9]+$#grafana:latest#g' grafana.yaml sed -ri 's#([a-z]+|[a-z]+-[a-z])(.grafana.net/grafana:)[0-9]+.[0-9]+.[0-9]+$#\1\2latest#g' grafana.yaml sed -i '/image:/s#docker.*#grafana:latest#g' grafana.yaml # 示例文本 containers: - name: grafana image: docker.grafana.net/grafana:7.5.2 image: docker-host.grafana.net/grafana:7.5.2 imagePullPolicy: IfNotPresent ports: - containerPort: 3000 name: http-grafana protocol: TCP
命令 | 含义 |
1s/old/new/ | 替换第1行内容old为new |
1,10s/old/new/ | 替换1行到10行的内容old为new |
1,+5s/old/new/ | 替换1行到6行的内容old为new |
/pattern1/s/old/new/ | 替换匹配pattern1的内容old为new |
/pattern1/,/pattern2/s/old/new/ | 替换匹配到pattern1的行直到匹配到pattern2的所有行内容old为new |
10,/pattern1/s/old/new/ | 替换第10行直到匹配到pattern1的所有行内容old为new |
二、awk相关
1、awk中引入shell变量方法
var="this a test" awk 'BEGIN{print "'"$var"'"}' var1="hello" var2="world" awk -v a=$var1 -v b=$var2 'BEGIN{print a,b}'
处理规则顺序: BEGIN{}//{}END{} BEGIN{} : BEGIN是在awk处理文本之前运行 // : 使用的匹配规则 {} :循环(每次只处理一行数据) END{} :当所有的处理全部执行完毕之后,执行END中的相关操作 示例: netstat -lntup | awk 'BEGIN{printf "%s\t%s\t%s\n","行号","协议","进程"} NR==15 && /sshd/ {printf "%s\t%s\t%s\n",NR,$1,$NF}END{print "结束"}'
2、awk内置字符串函数
gsub(r,s) 在整个$0中,用s代替r
gsub(r,s,t) 在整个t中,用s代替r #替换字符串
index(s,t) 返回s中字符串t的第一位置 #未用过
length(s) 返回s长度 #c语言strlen
match(s,r) 测试s是否包含匹配r的字符串 #c语言strcmp
split(s,a,fs) 使用分隔符fs将字符串s划分为指定序列a
sprint(fmt,exp) 输出经过fmt格式化后的exp
substr(s,0) 返回字符串s中从第0个字符开始到s字符串的结尾
substr(s,0,n) 返回字符串s中从第0个字符开始到长度为n的部分
3、printf格式化输出
.prec 最大字符串长度,或小数点右面的位数
%c ASCII字符
%d 整型
%e 科学计数法
%f 浮点型 #使用小数点后2位%.2f (用于除法后)
%g awk决定哪种浮点数转换e或者f
%o 八进制
%s 字符串
%x 十六进制
# 表示是从第3列的第6个字符开始,一直到设定的分隔符","结束. awk -F ',' '{print substr($3,6)}' # 查看/api_jsonrpc.php被访问的次数 awk -F '[ ]' '/\/api_jsonrpc.php/{ipaddr[$1$7]++}END{for(i in ipaddr){print i,ipaddr[i]}}' access_log # 状态码为200的html页面($5:$status;$7:$request;$9:$http_referer;substr($9,0,30):表示是从$9列的第0个字符开始,截取30个字符结束) find /var/log/nginx -type f -name "access_*_*.log" -exec awk -F "[||]" '($5 ~ /\.html\s/ && $7 ~ 200){print $7""$5""substr($9,0,30)}' {} \; # 查看nginx服务客户端连接 netstat -ntp | awk -F '[ :]+' '/[0-9]+\/nginx/{if($6 != "127.0.0.1"){print $6}}'
4、awk中使用的shell命令的3种方法:
1)、使用system()
awk程序中我们可以使用system() 函数去调用shell命令
root@ubuntu:~# awk 'BEGIN{system("echo abc")}' abc root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{v1="echo";v2="abc";system(v1" "v2)}' abc root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{v1="echo";v2="abc";system(v1 v2)}' /bin/sh: echoabc: command not found root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{v1=echo;v2=abc;system(v1" "v2)}' root@ubuntu:~#
从上面的例子,我们简单的分析一下awk是怎样调用system的:
如果system()括号里面的参数没有加上双引号的话,awk认为它是一个变量,它会从awk的变量里面把它们先置换为常量,然后再回传给shell
如果system()括号里面的参数有加上双引号的话,那么awk就直接把引号里面的内容回传给shell,作为shell的“命令行”
2)、使用print cmd | "/bin/bash"
root@ubuntu:~# awk 'BEGIN{print "echo","abc"| "/bin/bash"}' abc root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{print "echo","abc",";","echo","123"| "/bin/bash"}' abc 123 root@ubuntu:~#
3)、使用cmd | getline var
root@ubuntu:~# awk 'BEGIN{"echo hello"" ""world" | getline var;print var}' hello world root@ubuntu:~# awk 'BEGIN{ "seq 1 5" | getline var;close("seq 1 5");print var}' # 只打印第一行 1 root@ubuntu:~# awk 'BEGIN{ while(("seq 1 5" | getline var)){print var};close("seq 1 5")}' # 打印所有结果 1 2 3 4 5 root@ubuntu:~#
说明:
getline为awk所提供的输入指令。getline一次读取一行数据,若读取成功则return 1,若读取失败则return -1,若遇到文件结束(EOF),则return 0;
getline的用法和例子:
当getline左右没有重定向符|或<时,getline读去当前文件的第一行并将数据保存到变量中,若是没有变量,则数据保存到$0中;因为awk在处理getline以前已经读入了一行,因此getline获得的返回结果是隔行的。
当getline左右有重定向符|或<时,getline做用于定向输入文件,因为该文件是刚打开,awk并无读入一行数据,而getline读入了一行数据,那么getline返回的是该文件的第一行,而不是隔行。
4)、总结
无论使用system()还是print cmd | "/bin/bash",awk都是新开一个shell,在相应的cmdline参数送回给shell,所以要注意当前shell变量与新开shell变量问题
root@ubuntu:~# abc=12345567890 root@ubuntu:~# awk 'BEGIN{system("echo $abc")}' root@ubuntu:~# root@ubuntu:~# export abc=12345567890 root@ubuntu:~# awk 'BEGIN{system("echo $abc")}' 12345567890 root@ubuntu:~# root@ubuntu:~# abc=1234567890 root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}' root@ubuntu:~# root@ubuntu:~# export abc=1234567890 root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}' 1234567890 root@ubuntu:~#
说明:
以上例子,没有export的话,那些变量都是只存在于当前shell变量中,所以都是echo不出来的 ,
而使用了 export的都是环境变量,所以awk调用新的shell时候,可以echo出来。
4、awk获取shell命令返回值
root@ubuntu:~# awk '{cmd="ls " $1 ">/dev/null 2>&1";rc=system(cmd);print "RC:", rc}' test.txt RC: 0 RC: 2
命令说明:
1) 首先我们新建一个cmd变量,把需要执行的shell命令拼接起来赋给cmd
2) 通过system来执行shell命令,把返回值付给rc变量
3) 把rc变量打印到屏幕输出
如果想把出错信息也显示到屏幕的话,把2>&1去掉即可。
通过输出的信息我们看到,第一个ls命令的返回值是0,第二个ls命令的返回值是2
参考链接:
https://www.cnblogs.com/DengGao/p/5935719.html
https://www.cnblogs.com/emanlee/p/3327576.html
http://www.zsythink.net/archives/tag/awk/
https://www.cnblogs.com/liwei0526vip/p/5644163.html # sed
https://www.gnu.org/software/sed/manual/sed.html # sed官方文档
https://www.gnu.org/software/gawk/manual/gawk.html # awk官方文档