SED 是一种功能强大的流编辑器,Linux及Unix环境中现有的功能最强大的数据处理引擎之一,SED 是 stream editor 的缩写,是一个流编辑器。
Sed
和 Cut
类似,是一个面向行处理的命令,以“行”为单位进行流处理,处理后的结果输出到标准输出,默认情况下不会对处理文件进行修改,因此Sed命令一定程度上很安全。
命令结构
sed [options] 'command' file
执行过程:
参数
-n:取消默认输出
-i:直接将修改写入文件 (-i.bak 先备份再修改)
-r:使用扩展正则
模式
d:删除,即 delete
a:追加,即 append
i:插入,即 insert
p:打印,即 print
s:替换,即 substitue
g:全局,即 global (仅用于替换模式)
中间部分是针对每行数据所要做的处理(操作),后接的文件是要处理的目标文件,如果忽略此参数,则 Sed 会把标准输入作为处理对象。
SED 一次处理一行内容。命令执行时会把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用命令会处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾,文件内容并没有实际改变。
举个栗子
例 1:
cat >>value.list<<'EOF'
#排名 名称 市值(亿美元) 所在国家 行业
NO. NAME VALUE(BillionDollars) Country-Industry
01 Apple 8858.88 USA CONSUMER ELECTRONICS
02 Google 8251.05 USA INTERNET
03 Microsoft 7257.14 USA INTERNET
04 Amazon 6756.09 USA INTERNET
05 Tencent 5724.75 CHN INTERNET
06 Facebook 5517.97 USA INTERNET
07 BerkshireHathaway 5363.00 USA INSURANCE
08 Alibaba 5256.00 CHN INTERNET
09 JPMorganChase 4035.98 USA BANK
10 ICBC 3958.31 CHN BANK
EOF
问题 1:
打印 value.list
中包含 Amazon
的行到 Facebook
的行
[root@localhost ~]# sed -n '/Amazon/,/Facebook/p' value.list | column -t
04 Amazon 6756.09 USA INTERNET
05 Tencent 5724.75 CHN INTERNET
06 Facebook 5517.97 USA INTERNET
问题 2:
打印 value.list
的第2,4,6行
[root@localhost ~]# sed -n '2p;4p;6p' value.list | column -t
NO. NAME VALUE(BillionDollars) Country Industry
02 Google 8251.05 USA INTERNET
04 Amazon 6756.09 USA INTERNET
问题 3:
打印 value.list
的偶数行
[root@localhost ~]# sed -n '2~2p' value.list | column -t
NO. NAME VALUE(BillionDollars) Country Industry
02 Google 8251.05 USA INTERNET
04 Amazon 6756.09 USA INTERNET
06 Facebook 5517.97 USA INTERNET
08 Alibaba 5256.00 CHN INTERNET
10 ICBC 3958.31 CHN BANK
Tips:
'2~2p' 表示从第二行开始每次增加2
,即偶数行。
例 2:
cat >>operator.list<<'EOF'
10086,CHINA-MOBILE,CMB
10010,CHINA-UNICOM,CUC
10001,CHINA-TELECOM,CTC
EOF
问题 1:
在 operator.list
最后追加以下两行
10050,CHINA-TIETONG,CTT
10060,CHINA-NETCOM,CNT
在知道最后一行的内容时可以用,在书写的时候为便于区分,推荐在 i
或 a
参数前面加一个反斜线。
[root@localhost ~]# sed '/10001,CHINA-TELECOM,CTC/i\10050,CHINA-TIETONG,CTT\n10060,CHINA-NETCOM,CNT' operator.list
10086,CHINA-MOBILE,CMB
10010,CHINA-UNICOM,CUC
10050,CHINA-TIETONG,CTT
10060,CHINA-NETCOM,CNT
10001,CHINA-TELECOM,CTC
也可以使用$
直接追加到末尾
[root@localhost ~]# sed '$a\10050,CHINA-TIETONG,CTT\n10060,CHINA-NETCOM,CNT' operator.list
10086,CHINA-MOBILE,CMB
10010,CHINA-UNICOM,CUC
10001,CHINA-TELECOM,CTC
10050,CHINA-TIETONG,CTT
10060,CHINA-NETCOM,CNT
问题 2:
在 operator.list
中包含 10050,CHINA-TIETONG,CTT
的一行前或后增加以下两行
10050,CHINA-TIETONG,CTT
10060,CHINA-NETCOM,CNT
在匹配行前插入
[root@localhost ~]# sed '/10010,CHINA-UNICOM,CUC/i\10050,CHINA-TIETONG,CTT\n10060,CHINA-NETCOM,CNT' operator.list
10086,CHINA-MOBILE,CMB
10050,CHINA-TIETONG,CTT
10060,CHINA-NETCOM,CNT
10010,CHINA-UNICOM,CUC
10001,CHINA-TELECOM,CTC
在匹配行后插入
[root@localhost ~]# sed '/10010,CHINA-UNICOM,CUC/a\10050,CHINA-TIETONG,CTT\n10060,CHINA-NETCOM,CNT' operator.list
10086,CHINA-MOBILE,CMB
10010,CHINA-UNICOM,CUC
10050,CHINA-TIETONG,CTT
10060,CHINA-NETCOM,CNT
10001,CHINA-TELECOM,CTC
小贴士:若记不住a与i的前后顺序,可以简单记为 a == after 后,i == infront 前。
问题 3:
在 operator.list
第二行后插入 XXXX
[root@localhost ~]# sed 'N;2a\XXXX' operator.list
10086,CHINA-MOBILE,CMB
10010,CHINA-UNICOM,CUC
XXXX
10001,CHINA-TELECOM,CTC
注意!这里的N
表示行号,必须搭配;
,后面的数字必须是[偶数],否则不生效(或插入到错误的位置)!
问题 4:
在 operator.list
中删除包含 10086
和 10010
的行
[root@localhost ~]# sed '/10086/,/10010/d' operator.list
10001,CHINA-TELECOM,CTC
问题 5:
在 operator.list
中替换全部数字为空
[root@localhost ~]# sed 's/[0-9]//g' operator.list
,CHINA-MOBILE,CMB
,CHINA-UNICOM,CUC
,CHINA-TELECOM,CTC
问题 6:
在 operator.list
中替换字母C
为F
[root@localhost ~]# sed 's/C/F/g' operator.list
10086,FHINA-MOBILE,FMB
10010,FHINA-UNIFOM,FUF
10001,FHINA-TELEFOM,FTF
[root@localhost ~]# sed 's/C/F/' operator.list
10086,FHINA-MOBILE,CMB
10010,FHINA-UNICOM,CUC
10001,FHINA-TELECOM,CTC
问题 7:
过滤出 /etc/passwd
中前五行每列第一个出现的用户名
[root@localhost ~]# sed 's/:.*$//' /etc/passwd | head -n5
root
bin
daemon
adm
lp
也可以使用 cut
命令实现
[root@localhost ~]# cut -d : -f 1 /etc/passwd | head -n5
root
bin
daemon
adm
lp
小结
- 在替换模式中,若不使用
g
则只会替换每一行第一个匹配到的字符,使用则全部替换。可以使用正则表达式进行匹配关键字。 - 在追加或插入模式中,每个匹配到的行前后都会被添加指定内容,并不是只有第一个匹配到行才会追加或者插入。
- 若想将改动写入文件请使用
-i
参数或>
重定向符号。
进阶使用
反向引用
[root@localhost ~]# echo "123456" | sed -r 's/(.*)/<\1>/g'
<123456>
[root@localhost ~]# echo "123456" | sed -r 's/(..)(..)(..)/\1<\2>\3/g'
12<34>56
使用()
将引用的内容保护起来,然后再使用\n
来引用前面保护的内容。
例 1:取出网卡IP地址
[root@localhost ~]# ip a | sed -rn 's#^.*t (.*)/.*$#\1#gp' | tail -n1
192.168.31.133
例 2:取出文件 /etc/hosts
八进制权限
[root@localhost ~]# stat /etc/hosts | sed -rn '4s#^.*s: \((.*)/-.*$#\1#gp'
0644
[root@localhost ~]# stat /etc/hosts | sed -rn '4s#^.*s: \(([0-9]+)/-.*$#\1#gp'
0644
扩展:正则表达式
基础正则
第一个符号 ^
(以……开头的行)
第二个符号 $
(以……结尾的行)
组合 ^$
(空行)
第三个符号 .
(任意一个字符)
第四个符号 \
(转义符,取消效果)
第五个符号 *
([]* 前面字符出现0次或者0次以上)
组合 .*
(所有任意符号 包含空行 有贪婪性 连续出现的字符 会匹配到最后一个)
第六个符号 []
([abc]相当于一个符号每次匹配一个字符,支持a-z、0-9等)
第七个符号 [^]
(相当于一个符号,每次匹配一个字符) [^abc]
表示找出除了a
除了b
除了c
扩展正则
第八个符号 +
(前一个字符连续出现1次或1次以上)一般与[]
配合,取出连续的字符
第九个符号 |
(或者)
第十个符号 ()
(表示一个整体 sed 反向引用、后向引用)
第十一个符号 {}
(连续出现)0{n,m} 前一个字符至少连续出现n次,最多连续出现m次
第十二个符号 ?
(前面一个字符连续出现0次或者1次)
重点:使用以上扩展正则表达式时需要使用 Sed
的 -r
参数。
举个栗子
去除文件中空行(空行、TAB、空格、混合)
[root@localhost ~]# awk '/^[\t ]*$/' file.txt
命令拼接
需求一:批量添加用户 test01
test02
test03
并设置密码为 123456
解决步骤:
第一步,生成用户名序列
[root@localhost ~]# echo test{01..3} | xargs -n1
test01
test02
test03
第二步,拼接出用户名添加格式
[root@localhost ~]# echo test{01..3} | xargs -n1 | sed 's#.*#useradd &#g'
useradd test01
useradd test02
useradd test03
第三步,拼接出设置密码格式
[root@localhost ~]# echo test{01..3} | xargs -n1 | sed 's#.*#useradd &; echo 123456 | passwd --stdin &#g'
useradd test01; echo 123456 | passwd --stdin test01
useradd test02; echo 123456 | passwd --stdin test02
useradd test03; echo 123456 | passwd --stdin test03
第四步,拼接执行格式
[root@localhost ~]# echo test{01..3} | xargs -n1 | sed 's#.*#useradd &; echo 123456 | passwd --stdin &#g' | bash
需求二:批量修改文件后缀名.txt
改成.conf
解决步骤:
第一步,查看文件名
[root@localhost test]# ll
total 0
-rw-r--r--. 1 root root 0 Jul 15 15:26 11.txt
-rw-r--r--. 1 root root 0 Jul 15 15:26 12.txt
-rw-r--r--. 1 root root 0 Jul 15 15:26 13.txt
-rw-r--r--. 1 root root 0 Jul 15 15:26 14.txt
-rw-r--r--. 1 root root 0 Jul 15 15:26 15.txt
第二步,提取出全部的文件名
[root@localhost test]# ls | sed -r 's/(.*)/\1/'
11.txt
12.txt
13.txt
14.txt
15.txt
第三步,拼接出改名格式
[root@localhost test]# ls | sed -r 's/(.*)(txt)/mv & \1conf/'
mv 11.txt 11.conf
mv 12.txt 12.conf
mv 13.txt 13.conf
mv 14.txt 14.conf
mv 15.txt 15.conf
第四步,拼接执行格式
[root@localhost test]# ls | sed -r 's/(.*)(txt)/mv & \1conf/' | bash
附录
参考链接
本文由 柒 创作,采用 知识共享署名4.0
国际许可协议进行许可。
转载本站文章前请注明出处,文章作者保留所有权限。
最后编辑时间: 2018-07-09 22:56 PM