sed
功能简介
sed的用途
sed是Stream Editor(流编辑器)的缩写,简称流编辑器;是用于处理文件的。
sed如何处理文件
sed是一行一行读取文件内容,并按照要求进行处理,把处理后的结果输出到屏幕。
- 示意图
- 原理
- 首先sed读取文件中的一行内容,把其保持在一个临时缓存区中(也称为模式空间)。
- 然后根据需求处理临时缓冲区中的行,完成后把该行发送到屏幕上。
- 总结
- 由于sed把每一行都保存在临时缓冲区中,对这个副本进行编辑,所以不会直接修改原文件
- sed主要用来自动编辑一个或多个文件,简化对文件的反复操作,对文件进行过滤和转换操作
使用方法–命令行格式
sed常见的语法格式有两种,一种叫命令行模式,另一种叫脚本模式。
语法格式
sed [选项] '处理动作' 文件名
常用选项
选项 | 说明 | 备注 |
---|---|---|
-e | 进行多项(多次)编辑 | |
-n | 取消默认输出 | 不自动打印模式空间 |
-r | 使用扩展正则表达式 | |
-i | 原地编辑(修改源文件) | |
-f | 指定sed脚本的文件名 |
常见处理动作
动作 | 说明 | 备注 |
---|---|---|
‘p’ | 打印 | |
‘i’ | 在指定行之前插入内容 | 类似vim中的大写O |
‘a’ | 在指定行之后插入内容 | 类型vim中的小写o |
‘c’ | 替换指定行的所有内容 | |
‘d’ | 删除指定行 |
常见定位
符号 | 说明 | 举例 |
---|---|---|
$ | 最后一行 | |
1 | 第一行 | |
1,3 | 第1到3行 |
举例说明
准备文件
cp /etc/passwd /tmp/test
格式
#格式
sed 选项 '定位+命令' 需要处理的文件
- 打印文件内容。
- p:打印内容
- -n:取消默认输出
sed -n 'p' /tmp/test #打印每一行,取消默认输出
sed -n '1p' /tmp/test #打印第1行
sed -n '2p' /tmp/test #打印第2行
sed -n '1,5p' /tmp/test #打印1到5行
sed -n '$p' /tmp/test #打印最后1行
- 增加文件内容。
- i:在地址定位的上面插入
- a:在地址定位的下面插入
- -n:取消默认输出
sed '$awang' /tmp/test #文件最后一行下面增加内容
sed 'awang' /tmp/test #文件的每一行下面都增加内容
sed '5awang' /tmp/test #文件的第5行下面增加内容
sed '$iwang' /tmp/test #文件最后一行上面增加内容
sed 'iwang' /tmp/test #文件的每一行上面都增加内容
sed '6iwang' /tmp/test #文件的第6行上面增加内容
sed '/^uucp/ihello' /tmp/test #以uucp开头行的上一行插入内容
sed '/^uucp/ahello' /tmp/test #以uucp开头行的下一行插入内容
- 修改文件内容。
- c:在地址定位处替换
sed '5chello world' /tmp/test #替换文件第5行内容
sed 'chello world' /tmp/test #替换文件所有内容
sed '1,5chello world' /tmp/test #替换文件1到5行内容为hello world
sed '^/user01/c88888' /tmp/test #替换以user01开头的行
- 删除文件内容。
- d:在地址定位处删除
sed '1d' /tmp/test #删除文件第1行
sed '1,5d' /tmp/test #删除文件第1到5行
sed '$d' /tmp/test #删除文件最后一行
- 搜索文件内容。
- s表示搜索;斜杠(/)表示分割符,可以自定义;动作一般是打印(p)或全局替换(g)。
# 格式
sed 's/搜索的内容/替换的内容/动作' 需要处理的文件
sed -n 's/root/ROOT/p' /tmp/test #搜索root,替换为ROOT并打印
sed -n 's/root/ROOT/gp' /tmp/test #全局搜索root,替换为ROOT并打印
sed -n 's/\/sbin\/nologin/wang/gp' /tmp/test #全局搜索/sbin/nologin,替换为wang并打印(使用\转义特殊字符)
sed -n 's@/sbin/nologin@wang@gp' /tmp/test #自定义分割符,全局搜索/sbin/nologin,替换为wang并打印
sed -n '1,5s@/sbin/nologin@wang@p' /tmp/test #自定义分割符,1到5行搜索/sbin/nologin,替换为wang并打印
sed -n '6,8s/^/#/p' /tmp/test #注释6到8行内容
sed -n '1,10s/^#//gp' /tmp/test #取消1到10行的注释
- 其他命令
-
命令列表
| 命令 | 解释 | 备注 |
| — | — | — |
| r | 从另外文件中读取内容 | |
| w | 内容另存为 | |
| & | 保存查找串以便在替换串中引用 | \(\) |
| = | 打印行号 | |
| ! | 对所选行以外的所有行应用命令,放到行数之后 | |
| q | 退出 | | -
举例
sed '3r /etc/hosts' /tmp/test #在/tmp/test的第3行下读取/etc/hosts文件的内容
sed '$r /etc/hosts' /tmp/test #在/tmp/test的最后1行下读取/etc/hosts文件的内容
sed '1,3w /tmp/test.bak' /tmp/test #将/tmp/test的1到3行保存到/tmp/test.bak文件中
sed '$w /tmp/test.bak' /tmp/test #将/tmp/test的最后一行行保存到/tmp/test.bak文件中
sed -n 's/^sync/#&/gp' /tmp/test #将/tmp/test的sync开头的前边添加#
sed -n 's/\(^rsync\)/\#1/gp' /tmp/test #将/tmp/test的sync开头的前边添加#,1表示匹配到的sync
sed -ne '/root/=' -ne '/root/p' /tmp/test #打印/tmp/test文件中包含root关键字的行号及行内容
sed -ne '/root/p' -ne '/root/=' /tmp/test #打印/tmp/test文件中包含root关键字的行号及行内容
sed -n '1,5p' /tmp/test #打印/tmp/test文件中1到5行
sed -n '1,5!p' /tmp/test #不打印/tmp/test文件中1到5行
sed '/shutdown/q' /tmp/test #打印/tmp/test文件中的内容,直到遇到shutdown关键字后退出
- 其他选项
- -e
在/tmp/test文件中的第5行的前面插入“hello word”;
在/tmp/test文件中的第8行下面插入“哈哈哈”;
并打印行号;
sed -e '5ihello word' -e '8a哈哈哈' -e '5=;8=' /tmp/test
过滤/etc/ssh/sshd_config中以“#”开头和空行
sed -e '/^#/d' -e '/^$/d' /etc/ssh/sshd_config
- -r
过滤/etc/ssh/sshd_config中以“#”开头和空行
sed -r '/^#|^$/d' /etc/ssh/sshd_config
过滤/etc/ssh/sshd_config中生效的行
sed -r '/^(#|$|;|\t#|\t$)/d' /etc/ssh/sshd_config
- -i
注意:选项n和i不能在一起使用;选项i不能和动作p一起使用;
sed -i '1,5s/^/#&' /etc/ssh/sshd_config
sed -i '17{s/YUNWEI/yunwei/;s#/bin/bash#/sbin/nologin#}'
- 结合正则使用
| 正则 | 说明 | 备注 |
| — | — | — |
| /key/ | 查询包含关键字的行 | sed -n ‘/root/p’ /tmp/test |
| /key1/,/key2/ | 匹配包含两个关键字之间的行 | sed -n ’ /adm/,/mysql/p’ /tmp/test |
| /key/,x | 从匹配关键字的行开始,到文件第x行之间的行(包含关键字所在行) | sed -n ‘/^ftp/,7p’ /tmp/test |
| x,/key/ | 从第x行开始到关键字的匹配行之间的行 | sed -n ‘7,/^ftp/p’ /tmp/test |
| x,y! | 不包含x到y行 | sed -n ‘3,7!p’ /tmp/test |
| /key/! | 不包含关键字的行 | sed -n ‘/ftp/!p’ /tmp/test |
使用方法–脚本格式
用法
- 使用
#方法一
#sed -f sed命令脚本 要操作的文件
sed -f sed_script.sh /tmp/test
#方法二
#./sed命令脚本 要操作的文件
chmod a+x sed_script.sh
./sed_script.sh /tmp/test
- sed命令脚本
#!/bin/sed -f
1,5d
s/root/hello/g
3i777
5i888
p
注意事项
- 脚本文件是一个sed的命令行清单。
- 在每行的末尾不能有任何空格、制表符或其他文本。
- 如果在一行中有多个命令,那么使用分号(;)分隔。
- 不需要且不可用引号包含命令。
- #号开头的为注释行。
awk
功能介绍
awk介绍
awk是一种编程语言,主要用于Linux或Unix下对文本和数据的处理。处理的数据可以是来自标准输入、一个或多个文件、其他命令输出。
awk的处理文件和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行想要的操作。
awk用途
- awk用来处理文件和数据,是Linux/Unix下的一个工具,也是一种编程语言。
- awk可以用来统计数据,比如网站的访问量、访问的IP量等。
- 支持条件判断,支持for和while循环。
awk原理
- awk使用一行作为输入,并将这一行赋值给内部变量$0,每一行也可以称为一个记录,以换行符(RS)结束。
- 每行被间隔符“:”(默认为空格或制表符)分解成字段(或域),每个字段存储再已经编号的变量中,从$1开始。
- awk如何知道用空格来分隔字段呢?
- 因为有一个内部变量FS来确定字段分隔符,初始时,FS赋值为空格。
- awk使用print函数打印字段,打印出来的字段会以空格分隔,因为$1与$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量即输出字段分隔符OFS,OFS默认为空格。
- awk处理完一行后,将从文件中获取另一行,并将其存储再$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕。
使用方式–命令模式
语法格式
awk 选项 '命令部分' 文件名
# 特别说明:
# 引用shell变量需要使用双引号括起来。
# 命令部分需要使用单引号括起来。
常用选项
- -F:定义字段分隔符,默认分隔符是空格;
- -v:定义变量并赋值;
命令部分说明
- 正则表达式,地址定位
'/root/{awk语句}' #类似sed中:'/root/p'
'NR==1,NR==5{awk语句}' #类似sed中:'1,5p'
'/^root/,/^ftp/{awk语句}' #类似sed中:'/^root/,/^ftp/p'
- {awk语句1;awk语句2;…}
'{print $0;print $1}' #类似sed中:'p'
'NR==5{print $0}' #类似sed中:'5p'
- BEGIN…END…
'BEGIN{awk语句};{处理中};END{awk语句}'
'BEGIN{awk语句};{处理中}'
'{处理中};END{awk语句}'
使用方式–脚本模式
用法
- 使用
#方法一
#awk 选项 -f awk命令脚本 要处理的文本文件
awk -f awk_script.sh /tmp/test
#方法二
#./awk命令脚本 要处理的文本文件
chmod a+x awk_script.sh
./awk_script.sh /tmp/test
- awk命令脚本
#!bin/awk -f
BEGIN{FS=":"}
NR==1,NR==3{print $1"\t"$NF}
注意事项
- 脚本文件是一个sed的命令行清单。
- 在每行的末尾不能有任何空格、制表符或其他文本。
- 如果在一行中有多个命令,那么使用分号(;)分隔。
- 不需要且不可用引号包含命令。
- #号开头的为注释行。
相关变量
常用内置变量和常用分隔符
变量 | 变量说明 | 备注 |
---|---|---|
$0 | 当前处理行的所有记录 | |
$1,$2, 3 , . . . , 3,..., 3,...,n | 文件中每行以间隔符号分割为不同字段 | awk -F: ‘{print $1,$3}’ |
NF | 当前记录的字段数(列数) | awk -F: ‘{print NF}’ |
$NF | 当前记录的最后一列字段 | awk -F: ‘{print $NF}’ |
$(NF-1) | 当前记录的倒数第二列字段 | awk -F: ‘{print $(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 '{print $0}' /etc/passwd
- 打印1到5行
awk 'NR==1,NR==5{print $0}' /etc/passwd
- 打印第1行或者第5行
awk 'NR==1 || NR==5{print $0}' /etc/passwd
- 打印3到5行
awk 'NR>=3 && NR<=5{print $0}' /etc/passwd
- 打印列数
awk -F: '{print NF}' /etc/passwd
- 打印第1列和最后一列
awk -F: '{print $1,$NF}' /etc/passwd
- 打印第3列和倒数第2列
awk -F: '{print $3,$(NF-1)}' /etc/passwd
- 打印第1,3,5,倒数第二列
awk -F: '{print $1,$3,$5,$(NF-1)}' /etc/passwd
分隔符使用举例
- 自定义分隔符,并自定义输出分隔符
awk -F: 'BEGIN{OFS="#####"};{print $1,$NF}' /etc/passwd
- 自定义分隔符,并自定义输出分隔符
awk 'BEGIN{FS=":";OFS="#####"};{print $1,$NF}' /etc/passwd
- 自定义分隔符,并自定义输出分隔符
awk 'BEGIN{FS=":"};{print $1"######"$NF}' /etc/passwd
相关进阶
print和pringf
print和printf都是格式化输出命令。print类似echo(自带换行功能);printf类似echo -n(取消换行功能)。
- print举例
date
date | awk '{print "月份: " $2 "\n年份:" $NF}'
cat /etc/passwd
awk -F: '{print "用户名:" $1 "\t UID号是:" $3}' /etc/passwd
- printf举例
#printf常用符号
%s #字符串类型 %-20s:左对齐,占20个字符的字符串类型
%d #数值类型 %-10d:左对齐,占10个字符的数值类型
- #表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,如需换行需要加\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 | %1-5s|\n", %1,$2,$3}' /etc/passwd
awk 'BEGIN{FS=":"};{printf "%-15s %-15s %-15s\n", $1,$6,$NF}' /etc/passwd
定义变量
在awk中可以定义变量,调用变量时无需使用“$”直接写变量名即可调用。
awk -v NUMBER=3 -F: '{print NUMBER}' /etc/passwd
awk -v NUBMER=3 'BEGIN{print NUMBER}'
BEGIN…END…
- 解释
- BEGIN:表示在程序开始前执行
- END:表示所有文件处理完成后执行
- 用法:awk 选项 ‘BEGIN{开始处理之前};{处理中};END{处理结束后}’ 要处理的文件
- 举例
#打印最后一列和倒数第二列
#举例一:
awk -F: 'BEGIN{print "Login_shell\t\tLogin_home\n********************"};{print $NF"\t\t"$(NF-1)};END{print "********************"}' /etc/passwd
#举例二:
awk 'BEGIN{FS=":";print "Login_shell\t\tLogin_home\n********************"};{print $NF"\t\t"$(NF-1)};END{print "********************"}' /etc/passwd
#打印/etc/passwd里的用户名、家目录及登录shell
awk -F: 'BEGIN{OFS="\t\t";print "u_name\t\th_dir\t\tshell\n********************"};{printf "%-20s %-20s %-20s\n", $1,$(NF-1),$NF};END{print "********************"}' /etc/passwd
正则表达式
-
运算符列表
| 运算符 | 说明 |
| — | — |
| == | 等于 |
| != | 不等于 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| ~ | 匹配 |
| !~ | 不匹配 |
| ! | 逻辑非 |
| && | 逻辑与 |
| || | 逻辑或 | -
举例
#从第一行开始匹配,到以lp开头行截止
awk -F: 'NR==1,/^lp/{print $0}' /etc/passwd
#打印第一行到第五行
awk -F: 'NR==1,NR==5{print $0}' /etc/passwd
#从以lp开头的行匹配到第10行
awk -F: '/^lp/,NR=10{print $0}' /etc/passwd
#从以root开头的行匹配到以lp开头的行
awk -F: '/^root/,/^lp/{print $0}' /etc/passwd
#匹配以root开头或者以lp开头的行
awk -F: '/^root/ || /^lp/{print $0}' /etc/passwd
awk -F: '/^root/;/^lp/{print $0}' /etc/passwd
#显示5-10行
awk -F: 'NR<10 && NR>5 {print $0}' /etc/passwd
awk -F':' 'NR>=5 && NR<=10 {print $0}' /etc/passwd
#打印30-39行以bash结尾的内容
awk 'NR>=30 && NR<=39 && $0 ~ /bash$/{print $0}' /etc/passwd
#打印30-39行不匹配以bash结尾的内容
awk 'NR>=30 && NR<=39 && $0 !~ /bash$/{print $0}' /etc/passwd
- 综合
#打印IP地址
ifconfig ens32 | awk 'NR==2 {print $0}' | awk -F' ' '{print $2}'
ip addr | awk '/ens32/ && /inet/ {print $0}' | awk -F'[/ ]+' '{print $3}'
ip addr | awk -F'[/ ]+' '/ens32/ && /inet/ {print $3}'
#解释
#[/ :]+表示匹配间隔符“:”、“/”和空格,并可以出现多次
#[]中可以定义多个分隔符;+表示多次重复出现;
流程控制
- if…
#格式:
awk 选项 '{if(判断表达式) {处理语句1;处理语句2;...}}' 文件名
#举例:
awk -F: '{if($3>=500 && $3<=60000) {print $1,$3}}' /etc/passwd
awk -F: '{if($3==0) {print $1"是管理员"}}' /etc/passwd
awk -F: 'BEGIN{if($(id -u)==0) {print "admin"}}' /etc/passwd
- if…else…
#格式:
awk 选项 '{if(表达式) {语句1;语句2;...} else {语句1;语句2;...}}'
#举例:
awk -F: '{if($3>=500 && $3 != 65534) {print $1"是普通用户"} else {print $1"不是普通用户"}}'
awk -F: '{if($(id -u)>=500 && $(id -u) != 65534) {print $1"是普通用户"} else {print $1"不是普通用户"}}'
- if…else if…else
#格式:
awk 选项 '{if(表达式1) {语句1-1;语句1-2;...} else if(表达式2) {语句2-1;语句2-1;...} else {语句3-1;语句3-2;...}}'
#举例:
awk -F: '{if($3==0) {print $1"是管理员"} else if($3>=1 && $3<=499 || $3==65534) {print $1"是系统用户"} else {print $1"是普通用户"}}'
awk -F: '{if($3==0) {i++} else if($3>=1 && $3<=499 || $3==65534) {j++} else {k++}};END{print "管理员个数:"i "\n系统用户个数为:"j "\n普通用户个数为:"k}'
循环结构
- for
#格式:
awk 'BEGIN {变量;for(表达式) {语句}}'
#举例:
awk 'BEGIN {for(i=1;i<=5;i++) {print i}}'
awk 'BEGIN {for(i=1;i<=5;i++) (sum+=i);{print sum}}'
awk 'BEGIN {for(i=1;i<=5;i++) (sum+=i);print sum}'
awk 'BEGIN {sum=0;for(i=1;i<=5;i++) sum+=i;print sum}'
awk 'BEGIN {for(i=1;i<=10;i+=2) print i}'
awk 'BEGIN {for(i=1;i<=10;i+=2) {print i}}'
- while
#格式:
awk 'BEGIN {变量;while(表达式) {语句}}'
#举例:
awk 'BEGIN {i=1;while(i<=5) {print i; i++}}'
awk 'BEGIN {i=1;while(i<=10) {print i; i+=2}}'
awk 'BEGIN {i=1;sum=0;while(i<=5) {sum+=i; i++}; print sum}'
awk 'BEGIN {i=1;while(i<=5) {(sum+=i) i++}; print sum}'
- 嵌套
#格式:
awk 'BEGIN {for(表达式) {for(表达式) {语句}};语句}'
awk 'BEGIN {变量;while(表达式) {变量;while(表达式) {语句}};语句}'
awk 'BEGIN {变量;while(表达式) {for(表达式) {语句}}}'
#举例:
awk 'BEGIN {for(y=1;y<=5;y++) {for(x=1;x<=y;x++) {printf x};print}}'
awk 'BEGIN {y=1;while(y<=5) {for(x=1;x<=y;x++) {printf x};y++;print}}'