第七章 流编辑
什么是sed
挑选编辑器
UNIX/Linux世界中,有许多的文本编辑器可供选择。例如,最常使用的VI和emacs。在有了自己最熟悉的编辑利器后,才能轻松处理UNIX下各种管理和编辑任务。
像VI,emacs这类编辑器,被称为交互式编辑器。交互式编辑器虽然很棒,但是当我们需要在程序中完成文本处理工作时,它就帮不上忙了。此时就需要一些能够在命令行完成的编辑工具。
我们期待一切管理流程都能自动化,包括能够以批处理的方式编辑文件。许多文本编辑的需求都是对文本的每一行进行相同的操作。这样的处理就能够用sed来完成。
sed号称流编辑器。什么是流编辑器呢?流编辑器可以对从管道这样的标准输入接收的数据进行编辑。因此,无需将要编辑的数据存储在磁盘上的文件中。因为可以轻易将数据管道输出到sed,所以,将sed用作强大的shell脚本中长而复杂的管道很容易。
Sed的版本
查看版本方式
[houchangren@ebsdi-23260-oozie ~]$ sed --version
GNU sed version 4.1.5
Copyright (C) 2003 Free SoftwareFoundation, Inc.
This is free software; see the source forcopying conditions. There is NO
warranty; not even for MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.
Sed实例
Sed的工作方式
sed通过对输入数据执行任意数量用户指定的编辑操作(命令)。sed是基于行的,因此
按顺序对每一行执行命令。然后,sed将其结果写入标准输出(stdout ),它不修改任何输入
文件。
参数列表参考:
http://www.cnblogs.com/edwardlost/archive/2010/09/17/1829145.html
示例:
[houchangren@ebsdi-23260-oozie shell]$ head -n5 /etc/passwd > /tmp/passwd.bak
[houchangren@ebsdi-23260-oozie shell]$cat /tmp/passwd.bak
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
[houchangren@ebsdi-23260-oozie shell]$ sed -e 'd' /tmp/passwd.bak
[houchangren@ebsdi-23260-oozie shell]$ sed -e '1d' /tmp/passwd.bak
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
[houchangren@ebsdi-23260-oozie shell]$ sed -e '3d' /tmp/passwd.bak
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
上方的‘d’就是参数应用就是默认的就是删除每行,指定数字就删除第几行的记录,第一次删除了第一行1行显示后四条。第二次删除第3条,显示剩余其他4条。
NOTE
在该例中,还有几件事要注意:
1)根本没有修改/tmp/passwd.bak这还是因为sed只读取在命令行指定的文件,将其用作输入-它不试图修改该文件。
2)要注意的事是sed是面向行的。’d’命令不是简单地告诉sed一下子删除所有输入数据。相反,sed逐行将/etc/passwd.bak的每一行读入其称为模式缓冲区的内部缓冲区一旦将一行读入模式缓冲区,它就执行’d’命令,然后打印模式缓冲区的内容(在本例中没有内容).如果不使用地址,命令将应用到所有行。
3)括起‘d’命令的单引号的用法。养成使用单引号来括起scd命令的习惯是个好主意,这样可以禁用shell扩展。
Sed工作的地址范围
指定命令的操作行区域,比如下边1-2行和3-6行,当然没有第6行,就只有多少删除多少了。
[houchangren@ebsdi-23260-oozie shell]$ sed -e '1,2d' /tmp/passwd.bak
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
[houchangren@ebsdi-23260-oozie shell]$ sed -e '3,6d' /tmp/passwd.bak
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
sed忽略注释
[houchangren@ebsdi-23260-oozie shell]$ cat /etc/rc.local
#!/bin/sh
#
# This script will be executed *after* allthe other init scripts.
# You can put your own initialization stuffin here if you don't
# want to do the full Sys V style initstuff.
touch /var/lock/subsys/local
hive --service hiveserver &
[houchangren@ebsdi-23260-oozie shell]$ sed -e '/^#/d' /etc/rc.local | more
touch /var/lock/subsys/local
hive --service hiveserver &
[houchangren@ebsdi-23260-oozie shell]$ sed -e '/^[^#]/d' /etc/rc.local | more
#!/bin/sh
#
# This script will be executed *after* allthe other init scripts.
# You can put your own initialization stuffin here if you don't
# want to do the full Sys V style initstuff.
规则表达式
Sed中使用的规则表达式字符
字符 | 描述 |
^ | 与行首匹配 |
$ | 与行尾匹配 |
. | 与任意一个字符匹配 |
* | 与前一个字符的零个或多个出现匹配 |
[] | 与[]之内的所有字符匹配 |
Sed规则表达式实例
规则表达式 | 描述 |
/./ | 将与包含至少一个字符的任何行匹配 |
/../ | 将与包含至少两个字符的任何行匹配 |
/^#/ | 将与以‘#’开头的任意行匹配,通常这是注释 |
/}$/ | 将与‘}’结束的任意行匹配 |
/} *$/ | 注意在}后面有一个空格,这将与‘}’后而跟随零个或多个空格结束的任意行匹配配 |
/[abc]/ | 将与包含小写字母‘a,b,c的任意行匹配 |
/^[abc]/ | 将与以a,b,c任何开始的任何行匹配 |
-n参数 这个选项告诉sed 除非明确要求打印模式空间,否则不这样做。
[houchangren@ebsdi-23260-oozie shell]$ sed -n -e '/^[echo]/p' user_login.sh
echo " user $1 is on"
else
echo " user $1 is off"
[houchangren@ebsdi-23260-oozie shell]$ sed -n -e '/[abc]/p' user_login.sh
#!/bin/bash
function user_login(){
echo " user $1 is on"
echo " user $1 is off"
[houchangren@ebsdi-23260-oozie shell]$ cat a.c
#include <stdio.h>
#include <math.H>
int main (){
// int base,n;
// scanf("%d,%d\n",&b,&n)
}
[houchangren@ebsdi-23260-oozie shell]$ sed -n -e '/main[[:space:]]*(/,/^ }/p' a.c | more
int main (){
// int base,n;
// scanf("%d,%d\n",&b,&n)
}
[houchangren@ebsdi-23260-oozie shell]$ sed -n -e '/^\//p' a.c | more
// int base,n;
// scanf("%d,%d\n",&b,&n)
强大的Sed功能
替换
替换公式: sed -e s[符号][要替换的字符][符号][替换后的字符][符号][g]
实例:
[houchangren@ebsdi-23260-oozie data]$ cattwister.txt //查看一信息
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
[houchangren@ebsdi-23260-oozie data]$ sed -e 's/wish/want/' twister.txt //替换每一行的第一个匹配
I want to wish the wish you wish to wish,but if you wish the wish the witch
wantes, I won't wish the wish you wish towish.
I want to wish the wish you wish to wish,but if you wish the wish the witch
wantes, I won't wish the wish you wish towish.
I want to wish the wish you wish to wish,but if you wish the wish the witch
wantes, I won't wish the wish you wish towish.
I want to wish the wish you wish to wish,but if you wish the wish the witch
wantes, I won't wish the wish you wish towish.
[houchangren@ebsdi-23260-oozie data]$ sed -e 's/wish/want/g' twister.txt //替换匹配到的所有的
I want to want the want you want to want,but if you want the want the witch
wantes, I won't want the want you want towant.
I want to want the want you want to want,but if you want the want the witch
wantes, I won't want the want you want towant.
I want to want the want you want to want,but if you want the want the witch
wantes, I won't want the want you want towant.
I want to want the want you want to want,but if you want the want the witch
wantes, I won't want the want you want towant.
[houchangren@ebsdi-23260-oozie data]$ sed -e '1,2s/wish/want/' twister.txt //替换1到2行的第一个匹配
I want to wish the wish you wish to wish,but if you wish the wish the witch
wantes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
[houchangren@ebsdi-23260-oozie data]$ sed -e '1,2s/wish/want/g' twister.txt //替换1到2行的所有匹配
I want to want the want you want to want,but if you want the want the witch
wantes, I won't want the want you want towant.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
I wish to wish the wish you wish to wish,but if you wish the wish the witch
wishes, I won't wish the wish you wish towish.
[houchangren@ebsdi-23260-oozie data]$
因为有的时候需要操作’/’符号,那么再用‘/’线
来做符号就不方便了,可以改成其他的,比如冒号‘:’
[houchangren@ebsdi-23260-oozie data]$ cat hivepath.txt
/usr/local/hive-0.7.1-cdh3u6/bin/hive
/usr/local/hive-0.7.1-cdh3u6/bin/hive
/usr/local/hive-0.7.1-cdh3u6/bin/hive
/usr/local/hive-0.7.1-cdh3u6/bin/hive
[houchangren@ebsdi-23260-oozie data]$ sed -e s:/usr/local:/usr/lib:g hivepath.txt
/usr/lib/hive-0.7.1-cdh3u6/bin/hive
/usr/lib/hive-0.7.1-cdh3u6/bin/hive
/usr/lib/hive-0.7.1-cdh3u6/bin/hive
/usr/lib/hive-0.7.1-cdh3u6/bin/hive
过滤所有的html标签实例
[houchangren@ebsdi-23260-oozie data]$ cat test.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
</HEAD>
<BODY>
I'mtest html
</BODY>
</HTML>
[houchangren@ebsdi-23260-oozie data]$ sed -e 's/<[^>]*>//g' test.html
New Document
I'mtest html
组合命令
组合多条命令
在同时使用多个命令的时候可以使用分号“;”
[houchangren@ebsdi-23260-oozie data]$ sed -e '=' fruit.txt // 等号=是显示行号
1
%%banae
2
banana
3
apple
4
Presimmon
5
%%banae
6
apple
7
Banana
8
orange
9
presimmon
[houchangren@ebsdi-23260-oozie data]$ sed -e '=;p' fruit.txt //显示行号和打印默认会打印所以两次
1
%%banae
%%banae
2
banana
banana
3
apple
apple
4
Presimmon
Presimmon
5
%%banae
%%banae
6
apple
apple
7
Banana
Banana
8
orange
orange
9
presimmon
presimmon
[houchangren@ebsdi-23260-oozie data]$ sed -n -e '=;p' fruit.txt //指定-n后打印p参数的命令
1
%%banae
2
banana
3
apple
4
Presimmon
5
%%banae
6
apple
7
Banana
8
orange
9
Persimmon
[houchangren@ebsdi-23260-oozie data]$ sed -n -e 'p' -e = fruit.txt //-e可以指定多个命令
%%banae
1
banana
2
apple
3
Presimmon
4
%%banae
5
apple
6
Banana
7
orange
8
presimmon
9
有时候当太多的命令需要连接一起执行的时候-e可能也不够使用了,可以使用-f指定文本,然后在文本中编写命令
[houchangren@ebsdi-23260-oozie data]$ cat hivepath.txt
/usr/local/hive-0.7.1-cdh3u6/bin/hive
/usr/local/hive-0.7.1-cdh3u6/bin/hive
/usr/local/hive-0.7.1-cdh3u6/bin/hive
/usr/local/hive-0.7.1-cdh3u6/bin/hive
//1d是删除一行,接着是/usr/local替换成/usr/bin,接着打印,接着显示行号
[houchangren@ebsdi-23260-oozie data]$ cat ../sed/test.sed
1d
s:/usr/local/:/usr/lib/:g
p
=
[houchangren@ebsdi-23260-oozie data]$ sed -n -f ../sed/test.sed hivepath.txt
/usr/lib/hive-0.7.1-cdh3u6/bin/hive
2
/usr/lib/hive-0.7.1-cdh3u6/bin/hive
3
/usr/lib/hive-0.7.1-cdh3u6/bin/hive
4
将多条命令应用到一个地址范围
在指定了一个地址范围比如 1-5行,然后执行多个操作
[houchangren@ebsdi-23260-oozie data]$ head -n10 /etc/passwd > pwd.piece
[houchangren@ebsdi-23260-oozie data]$ cat pwd.piece
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
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/etc/news:
[houchangren@ebsdi-23260-oozie data]$ sed -n -e'1,5{s:/bin/bash:/bin/sh:g;s/:/|/g;p}' pwd.piece
[houchangren@ebsdi-23260-oozie data]$ sed -n -e '1,5{s:/bin/bash:/bin/sh:g;s/:/|/g;p}' pwd.piece
root|x|0|0|root|/root|/bin/sh
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
[houchangren@ebsdi-23260-oozie data]$
[houchangren@ebsdi-23260-oozie data]$ cat ../sed/pwd.sed
1,5{
s:/bin/bash:/bin/sh:g
s/:/|/g
p
}
[houchangren@ebsdi-23260-oozie data]$ sed -n -f ../sed/pwd.sed pwd.piece
root|x|0|0|root|/root|/bin/sh
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
实例的例子
LINUX和DOS/Windows系统纯文本格式的换行方式是不同的。这个脚本将UNIX风格的文本转换成DOS/windows格式。你可能知道,基于DOS、windows的文本文件在每一行末尾有一个CR(回车)和LF(换行),而UNIX文本只有一个换行。有时可能需要将某unix文本移至
Windows系统,该脚本将为你执行必需的格式转换.
>>> sed -e ‘s/$/\r/’myunix.txt > mydos.txt
在该脚本中,‘$’规则表达式将与行的末尾匹配,而`\r'告诉sed在其之前插入个回车。
在换行之前插入回车,每一行立即就以CR/LF结束。
反之,有好多的时候下载的网络文件是dos/windows文件,在unix操作确实有问题,比如bash。用sed调用将把dos/windows格式的文本转换成可信赖的unix格式
>>> sed –e ‘s/.$//’ mydos.txt >myunix.txt
该脚本的工作原理很简单:替代规则表达式与一行的的最末字符匹配,而该字符恰好就是回车。我们用空字符替换它,从而将其从输出中彻底删除。如果使用改脚本,并注意到己经删除了输出中每行的最末字符,那么,你就指定了已经是UNIX式的文本文件。
Sed实践
要求:
1. 把“小明“的名字改成“李小明”;
2. 删除头三行
3. 显示5-10行
4. 删除包含“排除“的行
5. 显示所有生日在Nov和Dec之间的行
6. 所有姓张开头的行,前边标记 ***
7. 用“试用期人员“替换包含”试用“的行
8. 把刘发明的生日 1986/11/11
9. 删除所有的空白行
10. 写一个脚本,将第一行插入Personnel File ,删除所有以500结尾的工资,显示文件内容,把电话号码和生日颠倒一下,在文件的结尾添加the end。
11.把包含“试用”的行中姓名提取出来,然后正行替换成“试用人员:”+name
数据内容:
[houchangren@ebsdi-23260-oozie data]$ cat persons.txt
小明:010-68239343:我是经理:1988/01/10:5000
黎明:010-68239343:我是经理:1988/08/10:5000
张学友:010-68239343:我是经理:1988/04/10:5000
周云飞:010-68239343:业务排除了。:1988/10/10:500
丽泽卡:010-68239343:没有描述:1988/12/10:2000
刘发明:010-68239343:没有描述:1988/11/10:5340
大荒西:010-68239343:没有描述:1988/10/10:1000
斯蒂芬:010-68239343:没有描述:1988/10/10:1000
甄格大:010-68239343:试用期中.:1988/10/10:200
任务操作:
1.
[houchangren@ebsdi-23260-oozie data]$ sed -n -e 's:小明:李小明:gp' persons.txt
李小明:010-68239343:我是经理:1988/01/10:5000
2.
[houchangren@ebsdi-23260-oozie data]$ sed -e '1,3d' persons.txt
周云飞:010-68239343:业务排除了。:1988/10/10:500
丽泽卡:010-68239343:没有描述:1988/12/10:2000
刘发明:010-68239343:没有描述:1988/11/10:5340
大荒西:010-68239343:没有描述:1988/10/10:1000
斯蒂芬:010-68239343:没有描述:1988/10/10:1000
甄格大:010-68239343:试用期中.:1988/10/10:200
3.
周云飞:010-68239343:业务排除了。:1988/10/10:500
丽泽卡:010-68239343:没有描述:1988/12/10:2000
刘发明:010-68239343:没有描述:1988/11/10:5340
4.
[houchangren@ebsdi-23260-oozie data]$ sed -e '/排除/d' persons.txt
小明:010-68239343:我是经理:1988/01/10:5000
黎明:010-68239343:我是经理:1988/08/10:5000
张学友:010-68239343:我是经理:1988/04/10:5000
丽泽卡:010-68239343:没有描述:1988/12/10:2000
刘发明:010-68239343:没有描述:1988/11/10:5340
大荒西:010-68239343:没有描述:1988/10/10:1000
斯蒂芬:010-68239343:没有描述:1988/10/10:1000
甄格大:010-68239343:试用期中.:1988/10/10:200
5.
[houchangren@ebsdi-23260-oozie data]$ sed -n '/[:::][0-9]*[:/:]1[1-2]/p' persons.txt
丽泽卡:010-68239343:没有描述:1988/12/10:2000
刘发明:010-68239343:没有描述:1988/11/10:5340
6.
[houchangren@ebsdi-23260-oozie data]$ sed -n 's/^张/***张/p' persons.txt
***张学友:010-68239343:我是经理:1988/04/10:5000
7.
[houchangren@ebsdi-23260-oozie data]$ sed -e 's/^.*试用.*$/试用期人员/g' persons.txt
小明:010-68239343:我是经理:1988/01/10:5000
黎明:010-68239343:我是经理:1988/08/10:5000
张学友:010-68239343:我是经理:1988/04/10:5000
周云飞:010-68239343:业务排除了。:1988/10/10:500
丽泽卡:010-68239343:没有描述:1988/12/10:2000
刘发明:010-68239343:没有描述:1988/11/10:5340
大荒西:010-68239343:没有描述:1988/10/10:1000
斯蒂芬:010-68239343:没有描述:1988/10/10:1000
试用期人员
8.
[houchangren@ebsdi-23260-oozie data]$ sed -n -e '/刘发明/s/:[0-9]*\/.*\/.*:/:1986\/11\/11:/gp' persons.txt
刘发明:010-68239343:没有描述:1986/11/11:5340
9.
[houchangren@ebsdi-23260-oozie data]$ sed -e '/^$/d' persons.txt
小明:010-68239343:我是经理:1988/01/10:5000
黎明:010-68239343:我是经理:1988/08/10:5000
张学友:010-68239343:我是经理:1988/04/10:5000
周云飞:010-68239343:业务排除了。:1988/10/10:500
丽泽卡:010-68239343:没有描述:1988/12/10:2000
刘发明:010-68239343:没有描述:1988/11/10:5340
大荒西:010-68239343:没有描述:1988/10/10:1000
斯蒂芬:010-68239343:没有描述:1988/10/10:1000
甄格大:010-68239343:试用期中.:1988/10/10:200
10.
[houchangren@ebsdi-23260-oozie data]$ cat ../sed/person.sed
/500$/d
s/\(.*\)\(:.*:\)\(.*\)\(:.*:\)\(.*\)/\1\4\3\2\5/g
1i personnel file
$a the end
[houchangren@ebsdi-23260-oozie data]$sed -f ../sed/person.sed persons.txt
personnel file
小明:1988/01/10:我是经理:010-68239343:5000
黎明:1988/08/10:我是经理:010-68239343:5000
张学友:1988/04/10:我是经理:010-68239343:5000
丽泽卡:1988/12/10:没有描述:010-68239343:2000
刘发明:1988/11/10:没有描述:010-68239343:5340
大荒西:1988/10/10:没有描述:010-68239343:1000
斯蒂芬:1988/10/10:没有描述:010-68239343:1000
甄格大:1988/10/10:试用期中.:010-68239343:200
the end
11.
[houchangren@ebsdi-23260-oozie data]$ sed -n -e '/试用/s/\(.*\):.*:.*:.*:.*/试用期人员:\1/gp' persons.txt | more
试用期人员:甄格大