一、sed工作原理
sed是一种流编程器,配合正则表达式使用来处理文本。
原理:首先,把当前处理的行存储在临时缓冲区(模式空间),接着用sed命令处理缓冲区中的内容,处理完成之后,把缓冲区的内容送往屏幕。接着处理下一行,这样处理下一行,这样不断重复,知道文件末尾。——文件内容并没有改变。
二、sed基本语法
sed OPTIONS… [SCRIPT] [INPUTFILE…]<=> sed 选项… [脚本] [要处理的文本文件…]注:SCRIPT指的是sed命令的脚本部分,它是一系列sed命令的集合,用于指定对输入文本的处理方式。
常见的选项:
-n | --quiet | --silent:安静模式,不输出模式空间中的内容。
理解:在一般sed用法中,所有来自stdin的数据一般都会被列出到屏幕上,但是如果加上-n参数后,则只有经过sed特殊处理的那一行才会被列出来。如果不加则会将文本空间中的内容和正在处理的内容都输出来
注意:加n,只输出改过的内容的行
-i :直接编辑原文件,而不是屏幕输出。
注意:默认不对原文件进行操作。
-e :直接在命令行模式上进行sed的动作编辑,多个子命令之间也可以用分号隔开。
如: sed -e 'command1;command2...' filename 或者 sed -e 'command1' -e 'command2' ……filename
-r :使用扩展正则表达式。
-f :直接将sed的动作写在一个文件内。
理解 :-f filename则可以执行filename内的sed动作。
三、模式空间中的编辑操作
1、地址界定
地址界定 | 示例 | 说明 |
---|---|---|
不写地址界定 | 对文件所有行进行处理 | |
num1,num2 | 1,3或者1,$ | 对文件指定范围的行(1-3)进行处理;如果是$,则表示文件的最后一行 |
num1,+N | 1,+3 | 对文件的num1行以及第N行(1,3)内容进行处理 |
first~step | 1~2 | 对文件指定步长(1,3,5,7,……)的行内容进行处理 |
/模式/ | /^root/,/r/| | 对任何能够被正则表达式匹配到的行进行处理 |
\%模式% | \%/r% | %(表示边界符),可以使用其他的边界符(例如#),对任何能够被正则表达式匹配到的行进行处理 |
/模式1/,/模式2/ | /^root/,/^adm/ | 表示正则表达式1和正则表达式2匹配到的行和两个正则表达式之间的所有行 |
0,/模式1/或者1,/模式1/ | 1,/^adm/ | 从第0/1行开始到能够被正则表达式匹配到的行之间的所有内容 |
相关使用:
/r/I :加I,表示可匹配 I 前的字符的大写,且只匹配 I前的字符
/模式1/,/模式2/ 的应用:
下列表示:匹配有root的行,直到匹配a的行,并且多次匹配,一直输出,直到匹配到a的行
2、常见的编辑命令
对文件内容的编辑命令 | 说明 | 示例 |
---|---|---|
d | 删除匹配到的行 | [root@node13 ~]#sed '1 d' file [root@node13 ~]#sed '/^$/d' /etc/hosts |
p | 打印匹配到的行 | [root@node13 ~]#sed '1 p' file |
a 文本内容 | 将文本内容添加到匹配到的行的下一行 | [root@node13 ~]#sed '1 a hello' file |
i 文本内容 | 将文本内容添加到匹配到的行的上一行 | [root@node13 ~]#sed '1 i hello' file |
c 文本内容 | 用文本内容替换匹配到的所有行 | [root@node13 ~]#sed '1,3 c hello' file |
s/模式/替换文本(replacement)/标志(flag) | 根据正则表达式进行匹配,将匹配到的内容替为replacement,flag可以指定g(表示全局替换,默认只替换每行的第一个),num 1(表示对匹配到的第几行的内容进行替换),i(不区分大小写),p(如果成功替换则打印) | [root@node13 ~]#sed '1 s#\ <print\>#echo#g' file [root@node13 ~]# sed '1 s/\bprint\b/echo/2' file |
r | 读入文件内容追加到匹配行后面 | [root@node13 ~]#sed '2 r /root/ceshi.sh' file |
R | 读入文件一行内容追加到匹配行后面 | [root@node13 ~]#sed '2 R /root/ceshi.sh' file |
w /dir/filename | 将匹配到的内容另存到/dir/filename | [root@node13 ~]# sed '1 w /dir1/file1' file |
补充:
①^$:表示空行
②vim在文本文件中多行添加 #:
ctrl+v——按下键选中行——按 I ——按 # —— 按esc
相关使用:
a 文本内容:
在匹配到old行的下一行添加内容,但是不改变file文件里面的内容,只是在模拟空间中处理;
(1)sed 's/north/hello/' datafile -- 替换每行第一个 north(2)sed 's/north/hello/g' datafile -- 全部替换(3)sed '1 s/north/hello/g' datafile -- 替换第一行所有的 north(4)sed '1 s/north/hello/' datafile -- 替换第一行第一个 north(5)sed '1 s/north/hello/2' datafile -- 只替换第一行第二个 northps : 巧用替换删除内容(不是删除行)(6)sed 's/north//' datafile -- 删除所有行的第一个 north(7)sed 's/north//g' datafile -- 删除全部的 north(8)sed '1 s/north//2' datafile -- 删除第一行第二个(9)sed 's/^.//' datafile -- 删除每行第一个字符(10)sed 's/^\(..\)./\1/' datafile -- 删除第 3 个字符(11)sed 's/^\<[a-Z]*[a-Z]\>//' datafile -- 删除每行第一个单词
特殊符号 | 说明 |
---|---|
! | 对指定行以外的所有行应用命令 |
= | 打印当前行行号 |
~ | “first~step” 表示从 first 行开始,以步长 step 递增 |
& | 代表匹配到的内容 |
; | 实现一行命令语句可以执行多条sed命令 |
{} | 对单个地址或地址范围执行批量操作 |
+ | 地址范围中用到的符号,做加法运算 |
相关使用:
[root@node13 ~]# sed '1 ! p' file # 打印除了第一行以外的行内容[root@node13 ~]# sed '/echo/ = ' file[root@node13 ~]# sed '1 s/echo/:&:/' file[root@node13 ~]# sed '1 s/echo/:&:/; 3 s/bea/aaa/' file[root@node13 ~]# sed '1,3 {p;=}' file 等同于 [root@node13 ~]# sed '1p;2p;3p;1=;2=;3 =' file
!:打印除了第一行之外的行
课后练习:
1 、把 /etc/passwd 复制到 /root/test.txt ,用 sed 打印所有行;2 、打印 test.txt 的 3 到 10 行;3 、打印 test.txt 中包含 ’root’ 的行;4 、删除 test.txt 的 15 行以及以后所有行;5 、删除 test.txt 中包含 ’bash’ 的行;6 、替换 test.txt 中 ’root’ 为 ’toor’ ;7 、替换 test.txt 中 ’/sbin/nologin’ 为 ’/bin/login’ ;8 、删除 test.txt 中 5 到 10 行中所有的数字;9 、删除 test.txt 中所有特殊字符(除了数字以及大小写字母);10 、在 test.txt 20 行到末行最前面加 ’aaa:’[root@localhost ~] # sed '20,$s/^.*$/aaa:&/g' test.txt11 、复制 /etc/grub2.cfg 到 /root/grub2.cfg, 删除文件中所有以空白开头的行行首的空白字符;[root@localhost ~] # sed 's/^[[:space:]]//' grub2.cfg12 、删除 /etc/fstab 文件中所有以 # 开头,后面至少跟一个空白字符的行的行首的 # 和空白字符[root@localhost ~] # sed 's/^#[[:space:]]*//' /etc/fstab13 、给文件 /root/anaconda-ks.cfg 每一行行首增加 # 号[root@localhost ~] # sed 's/^.*$/#&/' /root/anaconda-ks.cfg14 、在 /etc/fstab 文件中不以 # 开头的行的行首增加 # 号;[root@localhost ~] # sed 's/^[^#]/#&/' /etc/fstab15 、处理 /etc/sysconfig/network-scripts/ 路径 , 使用 grep 和 sed 命令取出其目录名和基名[root@localhost ~] # echo "/etc/sysconfig/network-scripts/" |sed -r's#^/(.*)/(.*)/#\1#' etc/sysconfig[root@localhost ~] # echo "/etc/sysconfig/network-scripts/" |sed -r's#^/(.*)/(.*)/#\2#'network-scripts[root@localhost ~] # echo "/etc/httpd/conf.d/host.conf" | sed -r 's#(^/.*/)[^/].* #\1#'/etc/httpd/conf.d/[root@localhost ~] # echo "/etc/httpd/conf.d/host.conf" | sed -r's#^/.*/([^/].*)#\1#'host.conf[root@localhost ~] # basename /etc/httpd/conf.d/host.confhost.conf[root@localhost ~] # dirname /etc/httpd/conf.d/host.conf/etc/httpd/conf.d[root@localhost ~] # echo "/etc/sysconfig/network-scripts/"|grep -o -E "[^/]+/?$"|grep -o -E " ^[^/] + "network-scripts[root@localhost ~] # echo "/etc/sysconfig/network-scripts/"|grep -o -E "(^/([^/] + /)*[^[:space:]])|^/ "|grep -o -E " ^/([^/] + /)* "|grep -o -E "(/[^/] + ) + |^/ "/etc/sysconfig16 、利用 sed 取出 ifconfig 命令中本机的 IPv4 地址[root@localhost ~] # ifconfig |sed -n '2p' | sed -r "s/.*inet[[:space:]]*//"|sed -r "s/[[:space:]]*netmask.*//"192 .168.168.12817 、统计 centos 安装光盘中 Package 目录下的所有 rpm 文件的以 . 分隔倒数第二个字段的重复次数[root@localhost ~] # ls /mnt/Packages/|grep "rpm$"|sed -r 's@.*\.(.*)\.rpm@\1@ '|sort|uniq -c1085 i6861216 noarch2319 x86_64
脚本练习:
1 、删除 /etc/grub2.conf 文件中所有以空白开头的行行首的空白字符2 、删除 /etc/fstab 文件中所有以 # 开头,后面至少跟一个空白字符的行的行首的 # 和空白字符3 、在 /root/install.log 每一行行首增加 # 号4 、在 /etc/fstab 文件中不以 # 开头的行的行首增加 # 号5 、利用 sed 取出 ifconfig 命令中本机的 IPv4 地址6 、关闭本机 SELinux 的功能7 、在 /etc/hosts 配置文件中添加内容
替换file中所有old为new,包括大写字符;标志分隔符可以用/或者#
加n:只输出改过的内容的行
-r:
-R:
删除前三个字符的中的第三个字符(用的子表达式)
!:打印除了第一行之外的行
&:与s替换结合,表示匹配到的字符前面添加内容