总结sed和awk的详细用法;
sed用法
sed(Stream EDitor)是一款流编辑器,用来对文本进行过滤与替换操作。其原理是:通过文件或管道读取文件内容,但是sed默认并不直接修改源文件,而是一次仅读取文件的一行至模式空间(pattern space)根据sed指令进行编辑并输出结果后清除模式空间,即所有的操作都是在模式空间中进行的。
语法格式
sed [option]… ‘script’ inputfile…
OPTIONS选项
-n,–quite,–silent:静默输出,即不输出模式中的内容至输出
-e script:使用多个脚本指令执行编辑
-f /PATH/TO/SCRIPT_FILE:从指定的文件中读取编辑脚本
-r:支持在脚本中使用正则表达式
-i,–in-place:直接在文件原处执行编辑,即修改源文件
SCRIPT,地址定界+编辑指令
地址定界
(1) 不给地址:对全文进行处理;
(2) 单地址
#:指定的行 $:文件的最后一行 /PATTERN/:被模式匹配到的每一行
(3) 地址范围
m,n:指定m行到n行 #,+n:指定#行到#+n行 /pat1/,/pat2/:匹配到的pat1到pat2之间的行 #,/pat/:第#行到匹配到pat
(4) 步进:~
1~2:所有奇数行,从一开始,步进2 2~2:所有偶数行,从二开始,步进2
注意:如果//中正则表达式为空,则匹配最近一次正则表达式的匹配地址!
编辑命令
d:删除
p:显示模式空间的内容
a \text:在行后面追加内容,支持使用\n(换行符)实现多行追加
i \text:在行前面插入内容,支持使用\n(换行符)实现多行追加
c \text:替换行为单行或多行文本,支持使用\n(换行符)
w /PATH/TO/SOMEFILE:保存模式空间匹配到的行至指定文件中
r /PATH/FROM/SOMEFILE:读取指定文件的文本流至模式空间中匹配到的行的行后
=:为模式空间中的行打印行号
!:取反条件
s/pattern/replacement/flags:替换,支持使用其他分隔符,如:s@@@, s###
替换标记(flags): #:替换行内匹配到的第#次的内容 g:行内全局替换 p:显示替换成功的行 w /PATH/TO/SOMEFILE:将替换后的结果保存至指定文件 replacement: &:用pattern匹配到的内容进行替换 \n:在pattern中使用\(\)指定时,匹配第n个子串
【难点】高级编辑命令:
h:把模式空间中的内容覆盖至保持空间中; H:把模式空间中的内容追加至保持空间中; g:把保持空间中的内容覆盖至模式空间中; G:把保持空间中的内容追加至模式空间中; x:把模式空间中的内容与保持空间中的内容互换; n:显示并清空模式空间,然后读取匹配到的行的下一行覆盖至模式空间; N:追加读取匹配到的行的下一行至模式空间中; d:删除模式空间中的行; D:删除多行模式空间中的所有行; 示例: sed -n 'n;p' FILE:显示偶数行; sed '1!G;h;$!d' FILE:逆序显示文件的内容; sed ’$!d' FILE:取出最后一行; sed '$!N;$!D' FILE:取出文件后两行; sed '/^$/d;G' FILE:删除原有的所有空白行,而后为所有的非空白行后添加一个空白行; sed 'n;d' FILE:显示奇数行; sed 'G' FILE:在原有的每行后方添加一个空白行;
awk用法
其用法博大精深,且听我细细道来
首先,grep,sed,awk三者区别,回顾一下:
grep, egrep, fgrep
文本过滤工具,只读不写,加上各种正则及关键字,那叫一个爽快。
sed
行编辑器,有模式空间及保持空间,实现文本行的编辑及输出。
awk
报告生成器,格式化文本输出;功能及其强大,不光可用正则,还可以使用条件判断语句,函数、数组,不愧为上古神器。
有一点很重要,也很激励人心,就是“结合awk与其他工具诸如grep和sed,将会使shell编程更加容易,也更有逼格。”
awk命令的使用格式:
awk [options] ‘program’ file1,file2,…
awk [options] ‘PATTERN { action }’ file1,file2,…
program与PATTERN { action }的关系
很多同学在刚开始学习awk的时候,这里常常犯迷糊,me too!所以我觉得这个关系先理清楚,对awk往后的学习是有帮助的。
program包括PATTERN和ACTION,PATTERN和ACTION最少得有一个,语句之间用分号分隔
【理解关键点】模式( pattern ) 用于匹配输入中的每行文本。对于匹配上的每行文本,awk 都执行对应的 动作( action )。模式和动作之间使用花括号隔开。awk 顺序扫描每一行文本,并使用 记录分隔符(一般是换行符)将读到的每一行作为 记录,使用 域分隔符( 一般是空格符或制表符 ) 将一行文本分割为多个 域, 每个域分别可以使用 $1, $2, … $n 表示。$1 表示第一个域,$2 表示第二个域,$n 表示第 n 个域。 $0 表示整个记录。模式或动作都可以不指定,缺省模式的情况下,将匹配所有行。缺省动作的情况下,将执行动作 {print},即打印整个记录。
先来说说ACTION
其中最常用的ACTION参数之一就是print和printf了,前者实现打印输出,后者实现格式化输出
语法:
print item1, item2, …
要点
(1) 逗号分隔符;
(2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式;
(3) 如省略item,相当于print $0,打印整行字符
printf命令,这个就很有内涵了
要点:
(1) FORMAT必须给出;
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面的每个item指定一个格式化符号;
语法:
printf 格式符/修饰符, item1, item2, …
格式符: %c: 显示字符的ASCII码; %d, %i: 显示十进制整数; %e, %E: 科学计数法数值显示; %f:显示为浮点数; %g, %G:以科学计数法或浮点形式显示数值; %s:显示字符串; %u:无符号整数; %%: 显示%自身; 修饰符: #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度; %3.1f -: 左对齐 +:显示数值的符号
记住哦,格式符和修饰符可以灵活组合使用
ACTION还支持以下干货,
(1) Expressions表达式
(2) Control statements:if, while等;
(3) Compound statements:组合语句;
(4) input statements
(5) output statements(print printf)
我们来看看控制语句:
(1)if(condition) {statments} :单分支if语句
(2)if(condition) {statments} else {statements} :双分支if语句
(3)while(conditon) {statments}
(4)do {statements} while(condition) :循环体
(5)for(expr1;expr2;expr3) {statements}
(6)break
(7)continue
(8)delete array[index]
(9)delete array
(10)exit
支持这么多,已经看傻,下面一个个来看看:
if-else
语法:if(condition) statement [else statement] ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd ~]# awk '{if(NF>5) print $0}' /etc/fstab ~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}' 使用场景:对awk取得的整行或某个字段做条件判断;
while循环
语法:while(condition) statement 条件“真”,进入循环;条件“假”,退出循环; ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg 使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用;
do-while循环
语法:do statement while(condition) 意义:至少执行一次循环体
for循环
语法:for(expr1;expr2;expr3) statement for(variable assignment;condition;iteration process) {for-body} ~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg 特殊用法: 能够遍历数组中的元素; 语法:for(var in array) {for-body}
switch语句
语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}
next
提前结束对本行的处理而直接进入下一行; ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
数组array
关联数组:array[index-expression] index-expression: (1) 可使用任意字符串;字符串要使用双引号; (2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”; 若要判断数组中是否存在某元素,要使用"index in array"格式进行; weekdays[mon]="Monday" 若要遍历数组中的每个元素,要使用for循环; for(var in array) {for-body}
函数
内置函数 数值处理: rand():返回0和1之间一个随机数; 字符串处理: length([s]):返回指定字符串的长度; sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容; gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容; split(s,a[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;
好,上边ACTION啰嗦完了,哈哈哈哈哈,下面就要高潮咧O(∩_∩)O哈哈~
PATTERN
PATTERN有什么,有很多,超乎你的想象,它支持
(1) empty:空模式,匹配每一行; (2) /regular expression/:仅处理能够被此处的模式匹配到的行; (3) relational expression: 关系表达式;【结果有“真”有“假”;结果为“真”才会被处理】; 【真:结果为非0值,非空字符串】这个跟bash的命令返回值不一样; (4) line ranges:行范围, startline,endline:/pat1/,/pat2/ 例子:[root@CentOS7 ~]# awk -F: '/^h/,/^u/{print $1}' /etc/passwd 注意: 不支持直接给出数字的格式 可以使用如下方式: ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd (5) BEGIN/END模式 BEGIN{}: 仅在开始处理文件中的文本之前执行一次; END{}:仅在文本处理完成之后执行一次 ;
选项[options]
-F:指明输入时用到的字段分隔符;
-v var=value: 自定义变量;
awk的options主要用来定义各种变量和使用各种內建变量。
内建变量
FS:input field seperator,默认为空白字符; OFS:output field seperator,默认为空白字符; RS:input record seperator,输入时的换行符; ORS:output record seperator,输出时的换行符; NF:number of field,字段数量 {print NF}, {print $NF} 它们之间是有区别的,NF是有多少个字段数量,而$NF表示最后一个字段的内容 NR:number of record, 行数; FNR:各文件分别计数;行数; $0:代表一行,读一行进行切片 FILENAME:当前文件名; ARGC:命令行参数的个数; ARGV:数组,保存的是命令行所给定的各参数; PS:在awk中要做变量替换,是不能用引号引起来的
自定义变量
(1) -v var=value #变量名区分字符大小写哦; (2) 在program中直接定义
好了,awk就介绍到这里,下面来写例子
例子1:显示/etc/passwd的账户
#cat /etc/passwd |awk -F ':' '{print $1}' root daemon bin sys
上边这种是awk+action的示例,每行都会执行action{print $1}。
-F指定域分隔符为’:’。
例子2:搜索/etc/passwd有root关键字的所有行
#awk -F: '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash
上边这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。
搜索支持正则,例如找root开头的: awk -F: ‘/^root/’ /etc/passwd
例子3:搜索/etc/passwd有root关键字的所有行,并显示对应的shell
# awk -F: '/root/{print $7}' /etc/passwd /bin/bash
上边这里指定了匹配了pattern(这里是root)的行才会执行action{print $7}
例子4:删除/boot/grub/grub.conf文件中所有行的行首的空白字符
sed ‘s/^[[:space:]]+//’ /boot/grub/grub.conf
这里的sed使用了查找替换,思路就是先查找文件中所有行的行首的空白字符,用正则的行首锚定空字符,之后查找替换为空,即删除。
例子5:删除/etc/fstab文件中所有以#开头,后跟至少一个空白字符的行的行首的#和空白字符
sed ‘s/^#[[:space:]]*//’ /etc/fstab
同样是查找替换的套路,参照例子4
例子6:把/etc/fstab文件的奇数行另存为/tmp/fstab.3
sed ‘1~2!d’ /etc/fstab > /tmp/fstab.3
sed ‘1~2w /tmp/fstab.3’ /etc/fstab
这里用到了sed地址定界中的步进+编辑命令,两种不同的编辑命令实现,真是飞刀又见飞刀,套路又见套路,套路就是熟悉其语法,命令,灵活组合使用。
例子7:echo一个文件路径给sed命令,取出其基名;进一步地,取出其路径名
路径名
echo “/tmp/test/fstab” | sed ‘s#[^/]+\?$##’
上边sed的#为分隔符,[^/]指匹配指定范围外的任意单个字符,
+:匹配其前面的字符1次或多次:即其前面的字符要出现至少1次;
\?:匹配其前面的字符0次或1次;即其前面的字符是可有可无的;
$:行尾锚定;用于模式的最右侧
基名
echo “/tmp/test/fstab” | sed ‘s#(\/.*\/)##’
上边的sed分隔符为#,用到了sed的查找替换、正则表达式及其分组,形式为\(正则表达式\) 正则为\/.*\/,其中\为转移符,正则抽取出来就是/.*/ 意思就是匹配到/开头的以/结尾期间的任意单个字符任意次。 各位应该明白了吧。
例子8:统计指定文件中所有行中每个单词出现的次数
awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}’ /etc/fstab
[root@CentOS7 ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab swap 2 fstab(5), 1 filesystems, 1 on 1 /etc/fstab 1 /boot 1 more 1 mount(8) 1 pages 1 '/dev/disk' 1 /dev/mapper/cl_centos7-swap 1 blkid(8) 1 See 1 /dev/mapper/cl_centos7-root 1 for 1 and/or 1 anaconda 1 / 1 findfs(8), 1 under 1 17:33:09 1 Created 1 UUID=fe2021fb-ac21-474d-8256-f72b87fc915a 1 0 6 info 1 Accessible 1 22 1 # 7 defaults 3 xfs 2 man 1 are 1 reference, 1 Mar 1 by 2 maintained 1 2017 1 Wed 1 [root@CentOS7 ~]#
7、统计当前系统上所有tcp连接的各种状态的个数;
netstat -n | awk ‘/^tcp/ {++state[$NF]} END {for(key in state) print key,”t”,state[key]}’
例子
root@xxx:~# netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"t",state[key]}' FIN_WAIT2 t 71 CLOSE_WAIT t 1 TIME_WAIT t 2049 ESTABLISHED t 1392 LAST_ACK t 3 FIN_WAIT1 t 4
8、统计指定的web访问日志中各ip的资源访问次数:
awk ‘{ip[$1]++}END{for(i in ip) print i,ip[i]}’ /opt/nginx/logs/access.log
9、写一个脚本:定义一个数组,数组元素为/var/log目录下所有以.log结尾的文件的名字;显示每个文件的行数;
[root@CentOS7 ~]# cat week15_title9.sh #!/bin/bash files=/var/log/*.log for i in $files do wc -l $i done
输出如下:
[root@CentOS7 ~]# ./week15_title9.sh 248 /var/log/boot.log 9 /var/log/openlmi-install.log 177 /var/log/vmware-install.log 326 /var/log/vmware-vmsvc.log 85 /var/log/vmware-vmusr.log 10 /var/log/wpa_supplicant.log 436 /var/log/Xorg.0.log 320 /var/log/Xorg.9.log 328 /var/log/yum.log [root@CentOS7 ~]#
10、写一个脚本,能从所有同学中随机挑选一个同学回答问题;进一步地:可接受一个参数,做为要挑选的同学的个数;
[root@CentOS7 ~]# cat week15_title10.sh #!/bin/bash if [ $1 ];then #判断有无脚本参数传入,如有则执行,没有就执行else的语句 for((i=1;i<=$1;i++));do a=$[$RANDOM%11] #定义一个0~10的随机数 echo $a done else a=$[$RANDOM%11] echo $a fi
11、授权centos用户可以运行fdisk命令完成磁盘管理,以及使用mkfs或mke2fs实现文件系统管理;
visudo centos ALL=(root) NOPASSWD:/sbin/fdisk,/sbin/mke2fs,/sbin/mkfs
12、授权gentoo用户可以运行逻辑卷管理的相关命令;
visudo gentoo ALL=(root) lvm
13、基于pam_time.so模块,限制用户通过sshd服务远程登录只能在工作时间进行;
vim /etc/ssh/sshd_config UsePAM yes #开启Pam模块认证 /lib64/security/pam_time.so #确保pam_time.so存在 vim /etc/pam.d/sshd 增加 account required pam_time.so vim /etc/security/time.conf 添加 *;*;*;MoTuWeThFr0900-1800
14、基于pam_listfile.so模块,定义仅某些用户,或某些组内的用户可登录系统;
[root@localhost ~]# vim /etc/sshd_userlist root centos gentoo chmod 600 /etc/sshd_userlist chown root /etc/sshd_userlist vim /etc/pam.d/sshd #auth required pam_listfile.so item=user sense=allow file=/etc/sshd_userlist onerr=succeed
原创文章,作者:N24_Jerry,如若转载,请注明出处:http://www.178linux.com/77539