Shell之文本三剑客

发布时间:2026/7/29 22:35:10
Shell之文本三剑客
目录一、grep工具行过滤二、sed介绍1. sed的工作流程2. sed使用方法2.1 命令行格式格式常用命令和选项其他命令讲解2.2 脚本格式用法注意事项3. sed和正则的综合运用三、awk介绍1. awk使用方式2. awk内部相关变量3. awk工作原理4. awk变量定义5. awk中BEGIN…END使用6. awk和正则的综合运用7. awk的脚本编程7.1 流程控制语句7.2 循环语句8.3 算数运算一、grep工具行过滤grep用于根据关键字进行行过滤 grep 【options】 keys filename OPTIONS: -i: 不区分大小写 -v: 查找不包含指定内容的行,反向选择 -w: 按单词搜索 -o: 打印匹配关键字 -c: 统计匹配到的次数 -n: 显示行号 -r: 逐层遍历目录查找 -A: 显示匹配行及后面多少行 -B: 显示匹配行及前面多少行 -C: 显示匹配行前后多少行 -l只列出匹配的文件名 -L列出不匹配的文件名 -e: 使用正则匹配 -E:使用扩展正则匹配 ^key:以关键字开头 key$:以关键字结尾 ^$:匹配空行 --colorauto 可以将找到的关键词部分加上颜色的显示 示例 # grep -i root passwd 忽略大小写匹配包含root的行 # grep -w ftp passwd 精确匹配ftp单词 # grep -w hello passwd 精确匹配hello单词;自己添加包含hello的行到文件中 # grep -wo ftp passwd 打印匹配到的关键字ftp # grep -n root passwd 打印匹配到root关键字的行好 # grep -ni root passwd 忽略大小写匹配统计包含关键字root的行 # grep -nic root passwd 忽略大小写匹配统计包含关键字root的行数 # grep -i ^root passwd 忽略大小写匹配以root开头的行 # grep bash$ passwd 匹配以bash结尾的行 # grep -n ^$ passwd 匹配空行并打印行号 # grep ^# /etc/vsftpd/vsftpd.conf 匹配以#号开头的行 # grep -v ^# /etc/vsftpd/vsftpd.conf 匹配不以#号开头的行 # grep -A 5 mail passwd 匹配包含mail关键字及其后5行 # grep -B 5 mail passwd 匹配包含mail关键字及其前5行 # grep -C 5 mail passwd 匹配包含mail关键字及其前后5行二、sed介绍1. sed的工作流程首先sed把当前正在处理的行保存在一个临时缓存区中也称为模式空间然后处理临时缓冲区中的行完成后把该行发送到屏幕上。sed把每一行都存在临时缓冲区中对这个副本进行编辑所以不会修改原文件。Sed主要用来自动编辑一个或多个文件简化对文件的反复操作编写转换程序等。2. sed使用方法sed常见的语法格式有两种一种叫命令行模式另一种叫脚本模式。2.1 命令行格式格式sed [option] sed的命令|地址定位 filename 说明引用shell script中的变量应使用双引号而非通常使用的单引号 option -e 进行多项编辑即对输入行应用多条sed命令时使用 -n 取消默认的输出 -f 指定sed脚本的文件名 -r 使用扩展正则表达式 -i inplace原地编辑修改源文件 sed 【选项】 sed命令或者正则表达式或者地址定位 文件名 地址定位用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址sed将处理输入文件的所有行。常用命令和选项参考文件 # cat 2.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 298374837483 172.16.0.254 10.1.1.1 p 打印行 d 删除行 # sed -n p a.txt # sed 1p a.txt # sed -n 1p a.txt # sed -n 1,5p a.txt # sed -n $p a.txt 打印最后一行 # sed 1d a.txt # sed -n 1d a.txt # sed 1d a.txt # sed 1,5d a.txt # sed $d a.txt i\ 在当前行之前插入文本。多行时除最后一行外每行末尾需用\续行 vim——O a\ 在当前行后添加一行或多行。多行时除最后一行外每行末尾需用“\”续行 vim—— o c\ 用此符号后的新文本替换当前行中的文本。多行时除最后一行外每行末尾需用\续行 整行替换 # sed $a99999 a.txt # sed a99999 a.txt # cat -n a.txt # sed 5chello world a.txt 将第五行整行文本替换成hello world # sed chello world a.txt 将全文每行文本替换成hello world # cat -n a.txt # sed 1,5chello world a.txt # sed i\ aaaaa\ bbbbb\ 88888 1.txt # sed $a\ yyyyy\ 8888 1.txt # sed /^user01/c888888 1.txt 以user01 开头的行整行内容替换成888888 命令2 r 从文件中读取输入行 w 将所选的行写入文件 # sed 3r /etc/hosts 2.txt # sed $r /etc/hosts 2.txt # sed /root/w a.txt 2.txt # sed /[0-9]{4}/w a.txt 2.txt # sed -r /([0-9]{1,3}\.){3}[0-9]{1,3}/w b.txt 2.txt ! 对所选行以外的所有行应用命令放到行数之后 # sed -n 1!p 1.txt # sed -n 4p 1.txt # sed -n 4!p 1.txt # cat -n 1.txt # sed -n 1,17p 1.txt # sed -n 1,17!p 1.txt s 用一个字符串替换行中的第一个所匹配到的字符串 g 在行内进行全局替换 # sed -n s/root/ROOT/p 1.txt # sed -n s/root/ROOT/gp 1.txt # sed -n s/^#//gp 1.txt # sed -n s/sbin/nologinitcastgp a.txt # sed -n s/\/sbin\/nologin/itcast/gp a.txt # sed -n 10s#/sbin/nologin#itcast#p a.txt # sed -n s/sbin/nologinitcastheimap 2.txt 注意搜索替换中的分隔符可以自己指定 # sed -n 1,5s/^/#/p a.txt 注释掉文件的1-5行内容 保存查找串以便在替换串中引用 \(\) # sed -n /root/p a.txt # sed -n s/root/#/p a.txt # sed -n s/^root/#/p passwd 注释掉以root开头的行 # sed -n -r s/^root|^stu/#/p /etc/passwd 注释掉以root开头或者以stu开头的行 # sed -n 1,5s/^[a-z].*/#/p passwd 注释掉1~5行中以任意小写字母开头的行 # sed -n 1,5s/^/#/p /etc/passwd 注释1~5行 或者 sed -n 1,5s/^/#/p passwd 1~5行开头加上# sed -n 1,5s/^#//p passwd 以#开头的替换成空 # sed -n /^root/p 1.txt # sed -n s/^root/#/p 1.txt # sed -n s/\(^root\)/#\1/p 1.txt # sed -nr /^root|^stu/p 1.txt # sed -nr s/^root|^stu/#/p 1.txt 打印行号 # sed -n /bash$/ passwd 打印以bash结尾的行的行号 # sed -ne /root/ -ne /root/p passwd # sed -n /nologin$/;/nologin$/p 1.txt # sed -ne /nologin$/ -ne /nologin$/p 1.txt 综合运用 # sed -n 1,5s/^/#/p 1.txt # sed -n 1,5s/\(^\)/#\1/p 1.txt 选项-e -r -i -e 多项编辑 -r 扩展正则 -i 修改原文件 # sed -ne /root/p 1.txt -ne /root/ # sed -ne /root/ -ne /root/p 1.txt 在1.txt文件中的第5行的前面插入“hello world”;在1.txt文件的第8行下面插入“哈哈哈哈” # sed -e 5ihello world -e 8a哈哈哈哈哈 1.txt -e 5;8 过滤vsftpd.conf文件中以#开头和空行 # grep -Ev ^#|^$ /etc/vsftpd/vsftpd.conf # sed -e /^#/d -e /^$/d /etc/vsftpd/vsftpd.conf # sed /^#/d;/^$/d /etc/vsftpd/vsftpd.conf # sed -r /^#|^$/d /etc/vsftpd/vsftpd.conf 过滤smb.conf文件中生效的行 # sed -e /^#/d -e /^;/d -e /^$/d -e /^\t$/d -e /^\t#/d smb.conf # sed -r /^(#|$|;|\t#|\t$)/d smb.conf # sed -e /^#/d -e /^;/d -e /^$/d -e /^\t$/d -e /^\t#/ smb.conf # grep ^[^a-z] 1.txt # sed -n /^[^a-z]/p 1.txt 过滤出文件中的IP地址 # grep -E ([0-9]{1,3}\.){3}[0-9]{1,3} 1.txt # sed -nr /([0-9]{1,3}\.){3}[0-9]{1,3}/p 1.txt # grep -o -E ([0-9]{1,3}\.){3}[0-9]{1,3} 2.txt # sed -nr /([0-9]{1,3}\.){3}[0-9]{1,3}/p 2.txt 过滤出ifcfg-eth0文件中的IP、子网掩码、广播地址 #ifconfig | grep -oE ([0-9]{1,3}\.){3}[0-9]{1,3} # ifconfig | sed -nr /([0-9]{1,3}\.){3}[0-9]{1,3}/p|tr -s : | cut -d: -f3,5,7|tr : \n -i 选项 直接修改原文件 # sed -i s/root/ROOT/;s/stu/STU/ 11.txt # sed -i 17{s/YUNWEI/yunwei/;s#/bin/bash#/sbin/nologin#} 1.txt # sed -i 1,5s/^/#/ a.txt 一定要注意 1、 -ni 不要一起使用 2、p命令 不要再使用-i时使用x 指定x行号 sed -n 5p 1.txt x,y 指定x到y行号 sed -n 1,5p 1.txt /key/ 查询包含关键字的行 sed -n /root/p 1.txt /key1/,/key2/ 匹配包含两个关键字之间的行 sed -n /^adm/,/^mysql/p 1.txt /key/,x 从匹配关键字的行开始到文件第x行之间的行包含关键字所在行sed -n /^lp/,7p x,/key/ 从第x行开始到与关键字的匹配行之间的行 x,y! 不包含x到y行 # sed -n /bash$/!p 1.txt 注意sed使用的正则表达式是括在斜杠线/之间的模式。 //以下命令是找出以lp开头或者以mail开头的行其他命令讲解y命令后面不用可以加g 该命令与UNIX/Linux中的tr命令类似字符按照一对一的方式从左到右进行转换。 正则表达式元字符对y命令不起作用。与s命令的分隔符一样斜线可以被替换成其它的字符。 s/xxx/xxx/ y/xxx/xxx/ # sed 39,41y/stu/STU/ /etc/passwd # sed 39,41y/stu:x/STU%/ /etc/passwd q 退出 # sed 5q 1.txt # sed /mail/q 1.txt # sed -r /^yunwei|^mail/q 1.txt # sed -n /bash$/p;10q 1.txt2.2 脚本格式用法# sed -f scripts.sed file //使用脚本处理文件 建议使用 ./sed.sh file 脚本的第一行写上 #!/bin/sed -f 3i7777 5i8888 $d s/hrllo/root/g注意事项 脚本文件是一个sed的命令行清单。commands 在每行的末尾不能有任何空格、制表符tab或其它文本。 如果在一行中有多个命令应该用分号分隔。 不需要且不可用引号保护命令 #号开头的行为注释3. sed和正则的综合运用1、正则表达式必须以”/“前后规范间隔 例如sed /root/d file 例如sed /^root/d file 2、如果匹配的是扩展正则表达式需要使用-r选来扩展sed grep -E sed -r ? () {n,m} | \d 注意 在正则表达式中如果出现特殊字符(^$.*/[]),需要以前导 \ 号做转义 egsed /\$foo/p file 3、逗号分隔符 例如sed 5,7d file 删除5到7行 例如sed /root/,/ftp/d file 删除第一个匹配字符串root到第一个匹配字符串ftp的所有行本行不找 循环执行 4、组合方式 例如sed 1,/foo/d file 删除第一行到第一个匹配字符串foo的所有行 例如sed /foo/,4d file 删除从匹配字符串”foo“开始到其后四行为止的行 例如sed /foo/,~3d file 删除从匹配字符串”foo“开始删除到3的倍数行文件中 例如sed 1~5d file 从第一行开始删每五行删除一行 例如sed -nr /foo|bar/p file 显示配置字符串foo或bar的行 例如sed -n /foo/,/bar/p file 显示匹配从foo到bar的行 例如sed 1~2d file 删除奇数行 例如sed 0~2d file 删除偶数行 sed 1~2!d file 5、特殊情况 例如sed $d file 删除最后一行 例如sed 1d file 删除第一行 6、其他 sed s/.// a.txt 删除每一行中的第一个字符 sed s/.//2 a.txt 删除每一行中的第二个字符 sed s/.//N a.txt 从文件中第N行开始删除每行中第N个字符Ngt;2 sed s/.$// a.txt 删除每一行中的最后一个字符三、awk介绍awk是一种编程语言主要用于在linux/unix下对文本和数据进行处理是linux/unix下的一个工具。数据可以来自标准输入、一个或多个文件或其它命令的输出。awk的处理文本和数据的方式逐行扫描文件默认从第一行到最后一行寻找匹配的特定模式的行并在这些行上进行你想要的操作。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GNU的gawk为例的在linux系统中已把awk链接到gawk所以下面全部以awk进行介绍。1. awk使用方式命令模式语法常用选项-F 定义字段分割符号默认的分隔符是空格-v 定义变量并赋值命令部分(commands)正则表达式地址定位/root/{awk语句} sed中 /root/p NR1,NR5{awk语句} sed中 1,5p /^root/,/^ftp/{awk语句} sed中/^root/,/^ftp/p{awk语句1;awk语句2;…}{print $0;print $1} sed中p NR5{print $0} sed中5p 注awk命令语句间用分号间隔BEGIN…END…BEGIN{awk语句};{处理中};END{awk语句} BEGIN{awk语句};{处理中} {处理中};END{awk语句}引用shell变量需用双引号引起awk 选项 commands 文件名脚本模式脚本执行方法1 awk 选项 -f awk的脚本文件 要处理的文本文件 注意类比 awk -f awk.sh filename 和 sed -f sed.sh -i filename 方法2 ./awk的脚本文件(或者绝对路径) 要处理的文本文件 ./awk.sh filename ./sed.sh filename脚本编写#!/bin/awk -f 定义魔法字符 以下是awk引号里的命令清单不要用引号保护命令多个命令用分号间隔 BEGIN{FS:} NR1,NR3{print $1\t$NF} ...2. awk内部相关变量变量变量说明备注$0当前处理行的所有记录$1,$2,$3…$n文件中每行以间隔符号分割的不同字段awk -F: ‘{print $1,$3}’NF当前记录的字段数列数awk -F: ‘{print NF}’$NF最后一列$(NF-1)表示倒数第二列FNR/NR行号FS定义字段之间间隔符‘BEGIN{FS“:”};{print $1,$3}’OFS定义输出字段分隔符默认空格‘BEGIN{OFS“\t”};print $1,$3}’RS输入记录分割符默认换行‘BEGIN{RS“\t”};{print $0}’ORS输出记录分割符默认换行‘BEGIN{ORS“\n\n”};{print $1,$3}’FILENAME当前输入的文件名示例# awk -F: {print $1,$(NF-1),$NF,NF} 1.txt # awk /root/{print $0} 1.txt # awk /root/ 1.txt # awk -F: /root/{print $1,$NF} 1.txt # awk -F: /root/{print $0} 1.txt # awk NR1,NR5{print $0} 1.txt # awk NR1,NR5;/^root/{print $0} 1.txt FS和OFS: # awk BEGIN{FS:};/^root/,/^lp/{print $1,$NF} 1.txt # awk -F: BEGIN{OFS\t\t};/^root/,/^lp/{print $1,$NF} 1.txt # awk -F: BEGIN{OFS};/^root/,/^lp/{print $1,$NF} 1.txt RS和ORS 修改源文件前2行增加制表符和内容 vim 1.txt root:x:0:0:root:/root:/bin/bash hello world bin:x:1:1:bin:/bin:/sbin/nologin test1 test2 # awk BEGIN{RS\t};{print $0} 1.txt # awk BEGIN{ORS\t};{print $0} 1.txt格式化输出print和printfprint函数 类似echo # date |awk {print Month: $2 \nYear: $NF} # awk -F: {print username is: $1 \t uid is: $3} /etc/passwd printf函数 类似echo -n # awk -F: {printf %-15s %-10s %-15s\n, $1,$2,$3} /etc/passwd # awk -F: {printf |%15s| %10s| %15s|\n, $1,$2,$3} /etc/passwd # awk -F: {printf |%-15s| %-10s| %-15s|\n, $1,$2,$3} /etc/passwd awk BEGIN{FS:};{printf %-15s %-15s %-15s\n,$1,$6,$NF} a.txt 1、%s 字符类型 strings %-20s 2、%d 数值类型 3、- 表示左对齐默认是右对齐 printf默认不会在行尾自动换行如果需要换行的时候需要加\n3. awk工作原理awk -F: {print $1,$3} /etc/passwdawk使用一行作为输入并将这一行赋给内部变量$0每一行也可称为一个记录以换行符(RS)结束每列被间隔符 ‘ : ’(默认为空格或制表符)分解成字段(或域)每个字段存储在已编号的变量中从$1开始。问awk如何知道用空格来分隔字段的呢答因为有一个内部变量FS来确定字段分隔符。初始时FS赋为空格awk使用print函数打印字段打印出来的字段会以空格分隔因为$1,$3之间有一个逗号。逗号比较特殊它映射为另一个内部变量称为输出字段分隔符OFSOFS默认为空格awk处理完一行后将从文件中获取另一行并将其存储在$0中覆盖原来的内容然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕4. awk变量定义# awk -v NUM3 -F: { print $NUM } /etc/passwd 打印第三列 # awk -v NUM3 -F: { print NUM } /etc/passwd 打印数字三有多少行就打印多少个 # awk -v num1 BEGIN{print num} 打印输出变量num对应的值 注意 awk中调用定义的变量不需要加$5. awk中BEGIN…END使用​ ①BEGIN表示在程序开始前执行​ ②END 表示所有文件处理完后执行​ ③用法BEGIN{开始处理之前};{处理中};END{处理结束后}BEGIN和END的核心特点就是只执行一次。示例打印最后一列和倒数第二列登录shell和家目录awk -F: BEGIN{print*********************************\nusername\tbash\t\n**********************************};{printf%-15s %-10s\n,$1,$NF};END{print*********************************} passwd ********************************* username bash ********************************** root /bin/bash bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin sync /bin/sync shutdown /sbin/shutdown halt /sbin/halt mail /sbin/nologin operator /sbin/nologin *********************************6. awk和正则的综合运用运算符说明等于!不等于大于小于大于等于小于等于~匹配!~不匹配!逻辑非逻辑与||逻辑或示例从第一行开始匹配到以lp开头行 awk -F: NR1,/^lp/{print $0 } passwd 从第一行到第5行 awk -F: NR1,NR5{print $0 } passwd 从以lp开头的行匹配到第10行 awk -F: /^lp/,NR10{print $0 } passwd 从以root开头的行匹配到以lp开头的行 awk -F: /^root/,/^lp/{print $0} passwd 打印以root开头或者以lp开头的行 awk -F: /^root/ || /^lp/{print $0} passwd awk -F: /^root/;/^lp/{print $0} passwd 显示5-10行 awk -F: NR5 NR10 打印5-10行以bash结尾的内容 #awk -F: NR5 NR10 $NF ~ /nologin$/ passwd 理解;号和||的含义 # awk -F: NR5 NR10 /nologin$/ 1.txt 并列条件的判断必须同时满足 # awk -F: NR5 NR10 ; /nologin$/ 1.txt 独立条件的判断 打印IP地址 ifconfig ens33|awk NR1{print $2}7. awk的脚本编程7.1 流程控制语句# 格式{ if(表达式)语句1;语句2;...} # 格式{if(表达式)语句;语句;...else语句;语句;...}} awk -F: {if($30){print $1是管理员}else{print $1是普 通用户} passwd # 格式{ if(表达式1)语句;语句...else if(表达式2)语句;语句...else if(表达式3)语句;语句...else语句;语句...} awk -F: {if($30){i} else if($31$31000){j} else{k}};END{print 超级管理员:i ORS 系统用户:j ORS 普通用户:k} passwd # 如果是普通用户打印默认shell如果是系统用户打印用户名 awk -F: {if($31$31000){print $1}else if($31000){print $NF}} passwd7.2 循环语句# while: awk BEGIN{ORS ;i1;while(i10){print i;i}{print \n}} # for: awk BEGIN{ORS ;for(i1;i10;i){print i}{print \n}} # 打印1~10中的奇数 awk BEGIN{i1;while(i10) {print i;i2}} # 循环嵌套 awk BEGIN{for(i1;i10;i){for(j1;ji;j){printf j};print}} 1 12 123 1234 12345 123456 1234567 12345678 123456789 打印99口诀表 awk BEGIN{for(i1;i10;i){for(j1;ji;j){printf %-2s*%-2s%-2s\t,j,i,i*j};print}} 循环的控制 break 条件满足的时候中断循环 continue 条件满足的时候跳过循环8.3 算数运算 - * / %(模) ^(幂2^3) 可以在模式中执行计算awk都将按浮点数方式执行算术运算 # awk BEGIN{print 11} # awk BEGIN{print 1**1} # awk BEGIN{print 2**3} # awk BEGIN{print 2/3}###二. awk统计案例1. 统计/etc/passwd 中各种类型shell的数量 # awk -F: {shells[$NF]};END{for(i in shells){print i:shells[i]个}} passwd /bin/sync:1个 /bin/bash:2个 /sbin/nologin:17个 /sbin/halt:1个 /sbin/shutdown:1个 snjsxnsjm:1个 2. 网站访问状态统计-当前时实状态 ; # ss -na| grep 80|awk {web_status[$2]};END{for(i in web_status){print i:web_status[i]}} LISTEN:3 ESTAB:4 UNCONN:4 3. 统计当前访问的每个IP的数量 ; # netstat -ant |grep :80 |awk -F: {ip_count[$8]};END{for(i in ip_count){print i,ip_count[i]} } |sort 4. 统计Apache/Nginx日志中某一天的PV量 - 统计日志; # grep 27/Jul/2017 mysqladmin.cc-access_log |wc -l 5. 统计Apache/Nginx日志中某一天不同IP的访问量t; # awk {ips[$1]};END{for(i in ips){print i,ips[i]}} /var/log/nginx/access.log 名词引入 名词VV Visit View访问次数 说明从访客来到您网站到最终关闭网站的所有页面离开计为1次访问。若访客连续30分钟没有新开和刷新页面或者访客关闭了浏览器则被计算为本次访问结束。 独立访客UV 名词UV Unique Visitor独立访客数 说明1天内相同的访客多次访问您的网站只计算1个UV。 网站浏览量PV 名词PVPageView (网站浏览量) 说明指页面的浏览次数用以衡量网站用户访问的网页数量。多次打开同一页面则浏览量累计。用户每打开一个页面便记录1次PV。 独立IPIP 名词IP独立IP数 说明指1天内使用不同IP地址的用户访问网站的数量。同一IP无论访问了几个页面独立IP数均为1本 篇 完 结 … …持 续 更 新 中 … …