- 浏览: 209500 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (391)
- java (18)
- python (3)
- ruby (4)
- linux (48)
- 网络 (9)
- 前端 (2)
- 社会、文化、哲学、人生、百态 (0)
- 工具 (10)
- 下载 (0)
- 常用地址 (0)
- tracert (0)
- mysql (8)
- 开源相关收藏 (1)
- 模块查看依懒 (1)
- watch使用 (1)
- Tcpdump (2)
- easy_install安装 (1)
- 构造redis批量删除脚本 (1)
- MYSQL 性能测试 (1)
- JAVA code encode utf-8 (1)
- linux nginx awk 实时 每妙 (1)
- mkpasswd (1)
- spring security oauth (1)
- jmap dump java memory Analyzer (1)
- JAVA DUMP (1)
- swap linux 过高 解决 (1)
- SWAP (1)
- jmap jstat jstack dump (1)
- java jconsole 的使用 (1)
- git 常用 (1)
- MYSQL 索引 动态 唯一 (1)
- TCP 三次握手 四次挥手 (1)
- linux date (1)
- 删除 空行 注释行 (1)
- maven3 yum linux install repository (1)
- linux git 搭建 (1)
- linux sar eth1 查看 流量 (1)
- sar (1)
- netstat ip 过滤 常用脚本 (1)
- Tcpdump 包分析网络连接过程 (1)
- net ipv4 tcp time wait tw recycle (0)
- /etc/sysctl.conf linux 网络 配置 (1)
- ss 网络连接查看 (比netstat 快很多,实时性牺牲) (1)
- MYSQL 关键字 (1)
- Linux 下多核CPU知识 (1)
- top (1)
- 令牌 证书 (1)
- mysql unix timestamp (1)
- 端口扫描 nc nmap (1)
- 204 http code 状态码 (1)
- ss -s ss -l (1)
- linux 常用 curl (1)
- linux sed 替换 换行 (1)
- centos yum install rpm install (1)
- spring-mvc源码解读 (1)
- 使用iftop查看实时的网络流量 (0)
- linux 命令 expect (1)
- HTTP (1)
- openssl ddif 加密 (1)
- iptables 详解 (1)
- python 虚拟化 VirtualEnv virtualenvwrapper (1)
- nginx (2)
- more less 实用技巧 (1)
- linux nginx (2)
- linux curl https ssl 证书 ca (1)
- openssl (1)
- php mysql linux (1)
- linux 虚拟机 虚拟 xen (0)
- linux 虚拟机 虚拟 xen kvm (1)
- linux perl 单行执行技巧 (1)
- mysql 查看库占用空间 表查用空间 (1)
- linux tcpdump (1)
- maven (1)
- sun.misc.Unsafe (1)
- OpenSSL生成证书 (1)
- http://blog.csdn.net/zzulp/article/details/8018751 (1)
- maven 本地 jar dependency (1)
- 计算JAVA代码行数最简单命令 sed (1)
- 常用的证书格式转换 rsa eg (1)
- 加密 解密 签名 (1)
- 分析jar包冲突 (1)
- 使用JMockit编写java单元测试 (1)
- Linux 技巧:让进程在后台可靠运行的几种方法 (1)
- 环境变量控制 (1)
- 5+ 个 tar 命令的用法,附示例 (1)
- scp自动输入密码 (1)
- ps axo pid (1)
- ppid (1)
- comm (1)
- pmem (1)
- lstart|grep mysql (0)
- lstart (1)
- etime|grep mysql (1)
- UML类图字少好理解 (1)
- HTTP经典文章 (1)
- git (1)
- Git常用命令 (1)
- LINUX 系统被攻击的分析过程 (1)
- NIO (1)
- LINUX 操作快捷键使用 (1)
- openSSL命令、PKI、CA、SSL证书原理 (1)
- shell (2)
- 转载 (1)
- mysqldump 可以直接dump->xml (1)
- VIM比较全面的文章 (1)
- eclipse regex 正则表达式 (1)
- synchronized (1)
- 锁 (1)
- java 正则表达式 regex (1)
- Reference Queue 引用 源码 (1)
- spring aop 源码 分析 (1)
- java @Cache @Transaction 注解 (1)
- spring aop (1)
- spring jdk proxy cglib 动态代理 性能比较 (1)
- spring proxy private public 代理限制 (1)
- spring transaction aop 事务 (1)
- spring autowire 注解注入 (1)
- 桥接 NAT NAT地址转换 内部网络 虚拟网络 (1)
- spring-web-mvc 源码解读 之 RequestMappingHandlerMapping (1)
- find atime mtime ctime -n n +n (1)
- android studio 快捷键初探 (1)
- android 源码阅读的计划 (1)
- 计算机网络学习-VLAN (1)
- sed 高级 合并行 (1)
- CAP 一致性 可用性 分布式容错性 (1)
- android lib so 库文件 (0)
- android lib so 库文件 移植 (1)
- android 不错的博文 (1)
- sourceinsight 源码 阅读 (1)
- Android Tab UI (1)
- 诗 (1)
- mysql 批处理 (0)
- netty 堆外内存 DirectByteBuffer (1)
- netty 并发 百万 推送 (1)
- Linux操作系统中内存buffer和cache的区别 (1)
- maven intellij target bytecode version (1)
- linux sleep()的实现原理 (1)
- android (2)
- javadoc 代码注释规范 (1)
- spring 自动注入bean auto (1)
- Photoshop CS6常用快捷键 (1)
- 股票 数据 机器 分析 (1)
- 批处理 (1)
- mysql -e (1)
- char (1)
- Unicode (1)
- 编码 (1)
- utf8 (1)
- utf-8 (1)
- utf16 (1)
- utf-16 (1)
- IntelliJ IDEA (1)
- ide (1)
- idea (1)
- intellij (1)
- 文件 (1)
- 目录 (1)
- 源代码 (1)
- CountDownLatch (1)
- CyclicBarrier (1)
- Semaphore (1)
- spring (1)
- linux 查看不同进制文件 (1)
- WebMvcConfigurationSupport (1)
- sdkman工具的使用 (1)
- http header (1)
- LINUX系统优化 (1)
最新评论
-
gelongmei:
威武我大酒神
shell脚本不换行刷新数据
sed 正则表达式
cat hotdog |sed 's/[0-9]//g'|sort|uniq -c|sort -nr -k2|more
1 正则表达式简介
正则表达式(Regular Expression)是一种描述文本(或字符串)模式的工具。正则表达式常用于查找文本的场合。想想一下我们日常生活中的例子,假如你想从电话本里找一个联系人的电话,而你又想不起联系人名字的准确拼法,你可以把电话本从头到尾翻一遍,如果电话本里联系人少的话也许并不是什么麻烦事,但想象一下如果这是记录着公司所有员工的电话本,你面临的工作便复杂得多了,有可能是从几百甚至几千条记录中寻找你想要的那条电话记录!而利用正则表达式则为解决这一问题提供了一种简便有效的方法。
正则表达式是一种描述具有某些共同特征的文本的文本,在不同的环境里有不同的格式,但其大致格式是相似的。本文将介绍Unix系统下的正则表达式。
其实,也许在你不清楚正则表达式是什么的时候你已经开始使用它了。想想Linux里一个最常用的命令:
ls *.tar
在这个命令里,*.tar 便是一个正则表达式,它是一个描述了这样的字符串的字符串:以任意数量的任意字符开头(*),后面紧接一个句点(.),然后再跟一个tar(这是在Unix Shell里表示的意思,在其他场合有不同的意思,后文将介绍)。星号(*)我们在DOS里常称之为“通配符(wildcard)”,而在正则表达式里我们称之为“元字符(metacharacter)”。下一章节我们将介绍正则表达式里常用的元字符。
2 正则表达式元字符和格式
在上一节里我们用一个例子介绍了什么是正则表达式的“元字符”。其实,元字符是一个或一组代替个或多个字符的字符。听起来有点拗口,但举一个例子也许你就明白了:元字符*用来匹配一个或多个的前一字符;而元字符 . 用来匹配一个任意的一个字符。正则表达式也可以不使用任何的元字符,一个简单的字符串 /piano/ (在Unix里正则表达式通常用一对斜线作为分隔符,后文在“正则表达式格式”部分中有介绍)也是一个正则表达式,只不过是准确匹配罢了。
下面列出了常用的正则表达式元字符,下一节将以实例的形式逐个介绍这些元字符的用法。需要注意的是,这些元字符并不是在所有的Unix (或Linux) 工具中都可以用,至于某个应用程序支持哪些元字符,可以参照该工具的用户手册。
表2.1 正则表达式元字符
元字符
功能
示例
匹配结果
^
行首定位符
/^supinfo/
匹配所有以supinfo开头的行
$
行尾定位符
/supinfo$/
匹配所有以supinfo结尾的行
\<
词首定位符
/\<supinfo/
匹配出现以supinfo为开头的词的行
\>
词尾定位符
/supinfo\>/
匹配出现以supinfo为结尾的词的行
.
匹配一个字符
/su…fo/
包含su,后面紧跟三个任意字符,然后紧跟着fo的行
*
匹配0个或多个前一字符
/_*supinfo/
supinfo前有0个或多个下划线的行
[]
匹配一组字符里的任意字符
/[Ss]pinfo/
包含Supinfo或supinfo的行
[x-y]
匹配指定范围内的字符
/[A-Z0-9]supinfo/
supinfo之前有一个A到Z或0到9的字符
[^ ]
匹配不在指定范围内的字符
/[^A-Z0-9]supinfo/
supinfo之前有一个既不是A到Z又不是0到9的字符
x\{m\}
x\{m,\}
x\{m, n\}
根据字符x出现的次数匹配:
m次;大于等于m次;大于等于m次但小于等于n次
/s\{2,5\}/
匹配有2到5个连续出现的s的行
\
转义元字符
/supinfo\. /
匹配包含supinfo,然后后面紧跟一个句点的行(没有 \ 的时候是匹配一个字符)
\(…\)
创建一个字符标签
/(SUPINFO):use\1NE/
括号中的字符被保存在标号为1的标签里,以后可以用\1来引用。标签编号从左到右依次为1,2,3……最多可以有9个标签。这个例子查找的是SUPINFO:后面跟着一个 use SUPINFONE的字符串
还有一点问题需要在这里提出,正则表达式有很多版本——至少存在两个版本:基本正则表达式和扩展正则表达式。在基本正则表达式中,原字符 | ,+ 和 ? 是不允许使用的。并且在使用含有圆括号和花括号的正则表达式时,圆括号和花括号都要用反斜线转义。在书写正则表达式时,比较好的做法是先写出整个正则表达式,然后再用反斜线将需要转义的字符转义。
正则表达式的格式
在Unix 中,正则表达式是被包含在一对斜线中的,斜线之间包含要匹配的字符(模式)。下面是几个例子:
/piano/ /[Pp]iano/ /*pinfo/ /s\{2,5\}oho/
3 正则表达式实例解析
下面我们就以具体的实例来看一下如何使用正则表达式。其中用黑体着重标出的是匹配到的字符串。
一个最简单的例子便是 /all/,比如下面一段文字:
John’s ball fell into the hole
John cried because it is all his life.
这个正则表达式不含任何的原字符,它查找的是字符串all,这个字符串all可以是独成一个单词,也可以是其它单词的一部分,因此正则表达式/all/既匹配ball里的all,也匹配完整的单词all。
下面我们着重讨论正则表达式里原字符的用法。
3.1 行首、行尾定位符
行首定位符^
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/^Bobby/
匹配位于行首的Bobby。
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/Bobby$/
匹配位于行尾的Bobby。
3.2 词首、词尾定位符
词首定位符 \<
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/\<Bo/
匹配位于词首的字符串Bo。
词尾定位符 \>
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby
Bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/ball\>/
匹配位于词尾的字符串ball。
在一个表达式中搭配使用词首定位符与词尾定位符
John’s ball fell into the hole
John cried because it is his whole life
/\<hole\>/
匹配以h作为单词开头并且以e作为单词结尾的模式hole。也就是说,字母h的前面是一个分隔单词的字符(比如空格或换行符),字母l的后面也是一个分隔单词的字符。这样,在这个例子中只有完整的单词hole会被匹配,而单词whole就不会被匹配。
3.3 匹配单个字符
匹配任意的一个字符 .
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/B…y/
匹配B开头后面紧跟三个任意字符,最后紧接着一个y的字符串。在这个例子中,Bobby和Bippy都会被匹配。
匹配0个或多个前一字符 *
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck balll
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/ al*/
这里的星号(*)匹配0个或多个在它前面的那个字符。前面曾提到过,正则表达式里的*和shell里的*作用是截然不同的。在shell里*表示任意个数的任意字符,而在正则表达式里,*只代表任意个数(包括0个)的前一字符,*可以看作和它前面那个字符是粘连在一起的,*只限制它前面那一个字符。这个正则表达式中的*匹配单独一个或多个连续的l,甚至也匹配一个l也没有的模式,所以,单个字符a也会被匹配。
3.4 匹配多个字符
匹配一组字符里的任意字符 [ ]
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck balll
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/[bw]all/
方括号匹配一组字符中的一个,这个正则表达式查找的是第一个字母是b或w,后面紧跟着all的字符串,因此在这个例子中,wall和ball都会被匹配。
匹配指定范围内的字符 [x-y]
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/B[a-z]p/
方括号里的短线(-)匹配某一范围内的一个字符,这个正则表达式将查找第一个字母是B,第二个字母是ASCII码介于a到z的字符(小写字母),第三个字母是p的字符串。
匹配不在指定范围内的字符 [^ ]
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/all[^A-Z0-9]/
方括号内的脱字符^是一个否定字符,这个正则表达式查找的是后面带一个特殊字符的all,这个特殊字符既不是小写字母又不是大写字母,也不是0到9的数字,比如它可以是一个标点符号或空格。
根据字符x出现的次数匹配 x\{m\} x\{m,\} x\{m, n\}
比如这个正则表达式:/Go\{2,5\}gle/将匹配G后面至少出现2个,最多有不超过5个o的模式。Google,Goooogle会被匹配,而Gogle和Goooooogle则不会被匹配。
3.5 转义字符
如果要匹配的字符串中含有正则表达式的原字符,需要用斜线将其转义,就像c语言里打印单引号 ’ 要写成 \’ 一样。这里有个例子:我们想要查找字符串google.com,要查找的字符串里含有正则表达式的原字符“.”,因此这个正则表达式要写成 /google\.com/,如果不用 \转义,找到的将是google后面跟一个任意的字符,然后跟一个com的字符串。这显然不一定是我们要找的。
3.6 字符标签
例如在下面一段文字里:
Occurence and happening are the most general. I mean, the words occurence and happening are most generally used.
在这段文字里有两个拼错的单词,Occurence和occurence,(其实应该是occurrence),我们可以在vi中用下面的表达式将其修改:
:1,$s/\([Oo]ccur\)ence/\1rence/
我们且不管这个vi命令的用法(其实它是一个替换命令,我们在后面介绍sed时还将提到)我们先拿出这个语句中的两个表达式:
/\([Oo]ccur\)ence/
\1rence
其中前一个是一个正则表达式。这个命令用后面的表达式内容替换前面的正则表达式匹配到的内容。vi编辑器将查找单词Occurence和occurence,如果找到,就把圆括号中的内容加上标签(Occur或occur被加上标签),因为这是第一个被标记的模式,所以被称为标签1。这个模式被保存在称为寄存器1的内存寄存器中。在第二个正则表达式中用\1引用寄存器1中的内容,\1被替换为寄存器中的内容,后面紧跟一个rence,于是,拼错的Occurence和occurence被改正为正确的Occurrence和occurrence。
3.7 原字符组合使用的例子
例1:/\<Bob.*all\>/
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/\<Bob.*all\>/
匹配以Bob开头,后面跟任意个数的任意字符,然后以all结尾的字符串。这里再次重复, *在Shell里表示任意个数的任意字符,而在正则表达式里表示任意个数的前一字符。与 . 配合使用表示任意个数(包括零个)的任意字符。实际上,* 也可以表示重复零次或任意次它前面的一组字符,我们称这一组(有时也可能是一个)字符为“原子”。当原子包括多个字符时,这多个字符要用圆括号括起来,并且需要将圆括号转义;当原子只含一个字符时,可以不用圆括号。在这个例子里,. 表示一个任意字符,紧跟着一个*表示重复0次或任意次前面的那个任意字符。而下面的例子
/\(sup\)*info/
则表示匹配在字符串info前有0个或多个sup的字符串,因此 supinfo, info, supsupinfo都会被匹配。
例2:/B[a-z][bp]*y$/
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/B[a-z][bp]*y$/
这个正则表达式匹配这样的字符串:开头字符是B,第二个字母是一个小写字母,后面紧跟0个或多个重复的b或p,最后跟一个y,并且这个字符串位于行的末尾。
4 sed原理及sed命令格式
4.1 Sed工作原理
sed是一个非交互式的流编辑器。所谓非交互式,是指使用sed只能在命令行下输入编辑命令来编辑文本,然后在屏幕上查看输出;而所谓流编辑器,是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕(除非取消了屏幕输出又没有显式地使用打印命令),接着读入下一行。整个文件像流水一样被逐行处理然后逐行输出。
下面我们看一下sed的工作过程。
sed不是在原输入上直接进行处理的,而是先将读入的行放到缓冲区中,对缓冲区里的内容进行处理,处理完毕后也不会写回原文件(除非用shell的输出重定向来保存结果),而是直接输出到屏幕上。sed运行过程中维护着两个缓冲区,一个是活动的“模式空间(pattern space)”,另一个是起辅助作用的“暂存缓冲区(holding space)”。一般情况下,每当运行sed,sed首先把第一行装入模式空间,进行处理后输出到屏幕,然后将第二行装入模式空间替换掉模式空间里原来的内容,然后进行处理,以此类推。
插图
一般情况下暂存缓冲区是用不到的,但有特殊的命令可以在模式空间与暂存缓冲区之间交换数据,后文将有介绍。由于sed对文本的所有操作都是在缓冲区里进行的,所以不会对原文件造成任何破坏。
4.2 Sed命令格式
sed的命令格式如下:
sed [-Options] [‘Commands’] filename
其中,Command是一个sed命令,sed命令一定要被包含在一对单引号中,以免被shell解释,其格式如下:
[address-range][sed-command]或
[Pattern-to-match][sed-command]
address-range是指要处理的行的范围,又叫地址范围;pattern-to-match是一个要匹配的模式,是一个正则表达式,sed-command是一个sed命令,用来对指定的行进行处理。下面是一个简单的例子:
sed –n ‘1,3p’ students
这个命令将文件students中的第1到3行打印到屏幕。注意,地址范围和sed命令之间没有空格,如果加入空格,sed也会将其忽略。参数-n用来取消默认输出。默认情况下,sed每读入一行到模式空间,无论是否对其进行处理,在读入下一行之前多要将模式空间中的内容输出到屏幕上。参数-n可以用来取消这种默认的输出,只有当用户用命令p时才将指定的行输出到屏幕。如果没有用参数-n而又对指定行执行了p命令,那么这些行将会被打印两次。
地址范围可以是一个数字,这个数字代表了一个行号;也可以是一个用逗号分隔的两个数字表示的范围(包括这两行)。范围可以是数字,正则表达式,或是两者的组合。
pattern-to-match是一个要匹配的模式,sed将会对所有匹配的行执行sed-command。其实,这里的pattern-to-match也可以看作是一个地址,这个地址是所有与指定模式匹配的行的行号。因此sed的格式可以归纳为一种:
sed [-Options] ‘[address-range][sed-command]’ filename
5 sed命令与选项
5.1 Sed命令
常用的sed命令如下表所列:
命令
功能
a\
在当前行之后插入一行或多行
c\
用新文本替换当前行中的文本,并开始新的一轮sed命令的执行
d
删除行
i\
在当前行之前插入文本
h
将模式空间里的内容拷贝到暂存缓冲区并替换原来暂存缓冲区的内容
H
将模式空间里的内容追加到暂存缓冲区
g
将里暂存缓冲区的内容拷贝到模式空间并替换原来模式空间的内容
G
将暂存缓冲区里的内容追加到模式空间
p
打印模式空间的内容
n
读入下一行到模式空间,并接着从下一条命令开始执行
q
直接退出sed,不继续执行其后的命令
r
读入指定文件的内容
w
将行写入文件
!
对所选行以外的行进行处理
s/regexp/replacement/flag
用replacement替换模式空间由regexp匹配到的内容
x
交换模式空间与暂存缓冲区的内容
y/source-chars/dest-chars/
将source-chars的字符换成对应的的dest-chars中的字符,source-chars和dest-chars中的字符个数要相同。source-chars和dest-chars中都不能有正则表达式。
=
打印当前行的行号,行号是令起一行打印的
#
sed脚本文件中领起注释
替换命令s/regexp/replacement/flag 中的flag:
flag
功能
g
进行全局替换。不使用此选项将只对该行匹配到的第一个结果进行替换
p
打印模式空间中的内容(替换之后的内容)
w filename
将替换之后的内容写入文件filename
在后面的章节“sed实例解析”中我们将以实例的形式详细介绍各个命令的用法。
1 正则表达式简介
正则表达式(Regular Expression)是一种描述文本(或字符串)模式的工具。正则表达式常用于查找文本的场合。想想一下我们日常生活中的例子,假如你想从电话本里找一个联系人的电话,而你又想不起联系人名字的准确拼法,你可以把电话本从头到尾翻一遍,如果电话本里联系人少的话也许并不是什么麻烦事,但想象一下如果这是记录着公司所有员工的电话本,你面临的工作便复杂得多了,有可能是从几百甚至几千条记录中寻找你想要的那条电话记录!而利用正则表达式则为解决这一问题提供了一种简便有效的方法。
正则表达式是一种描述具有某些共同特征的文本的文本,在不同的环境里有不同的格式,但其大致格式是相似的。本文将介绍Unix系统下的正则表达式。
其实,也许在你不清楚正则表达式是什么的时候你已经开始使用它了。想想Linux里一个最常用的命令:
ls *.tar
在这个命令里,*.tar 便是一个正则表达式,它是一个描述了这样的字符串的字符串:以任意数量的任意字符开头(*),后面紧接一个句点(.),然后再跟一个tar(这是在Unix Shell里表示的意思,在其他场合有不同的意思,后文将介绍)。星号(*)我们在DOS里常称之为“通配符(wildcard)”,而在正则表达式里我们称之为“元字符(metacharacter)”。下一章节我们将介绍正则表达式里常用的元字符。
2 正则表达式元字符和格式
在上一节里我们用一个例子介绍了什么是正则表达式的“元字符”。其实,元字符是一个或一组代替个或多个字符的字符。听起来有点拗口,但举一个例子也许你就明白了:元字符*用来匹配一个或多个的前一字符;而元字符 . 用来匹配一个任意的一个字符。正则表达式也可以不使用任何的元字符,一个简单的字符串 /piano/ (在Unix里正则表达式通常用一对斜线作为分隔符,后文在“正则表达式格式”部分中有介绍)也是一个正则表达式,只不过是准确匹配罢了。
下面列出了常用的正则表达式元字符,下一节将以实例的形式逐个介绍这些元字符的用法。需要注意的是,这些元字符并不是在所有的Unix (或Linux) 工具中都可以用,至于某个应用程序支持哪些元字符,可以参照该工具的用户手册。
表2.1 正则表达式元字符
元字符
功能
示例
匹配结果
^
行首定位符
/^supinfo/
匹配所有以supinfo开头的行
$
行尾定位符
/supinfo$/
匹配所有以supinfo结尾的行
\<
词首定位符
/\<supinfo/
匹配出现以supinfo为开头的词的行
\>
词尾定位符
/supinfo\>/
匹配出现以supinfo为结尾的词的行
.
匹配一个字符
/su…fo/
包含su,后面紧跟三个任意字符,然后紧跟着fo的行
*
匹配0个或多个前一字符
/_*supinfo/
supinfo前有0个或多个下划线的行
[]
匹配一组字符里的任意字符
/[Ss]pinfo/
包含Supinfo或supinfo的行
[x-y]
匹配指定范围内的字符
/[A-Z0-9]supinfo/
supinfo之前有一个A到Z或0到9的字符
[^ ]
匹配不在指定范围内的字符
/[^A-Z0-9]supinfo/
supinfo之前有一个既不是A到Z又不是0到9的字符
x\{m\}
x\{m,\}
x\{m, n\}
根据字符x出现的次数匹配:
m次;大于等于m次;大于等于m次但小于等于n次
/s\{2,5\}/
匹配有2到5个连续出现的s的行
\
转义元字符
/supinfo\. /
匹配包含supinfo,然后后面紧跟一个句点的行(没有 \ 的时候是匹配一个字符)
\(…\)
创建一个字符标签
/(SUPINFO):use\1NE/
括号中的字符被保存在标号为1的标签里,以后可以用\1来引用。标签编号从左到右依次为1,2,3……最多可以有9个标签。这个例子查找的是SUPINFO:后面跟着一个 use SUPINFONE的字符串
还有一点问题需要在这里提出,正则表达式有很多版本——至少存在两个版本:基本正则表达式和扩展正则表达式。在基本正则表达式中,原字符 | ,+ 和 ? 是不允许使用的。并且在使用含有圆括号和花括号的正则表达式时,圆括号和花括号都要用反斜线转义。在书写正则表达式时,比较好的做法是先写出整个正则表达式,然后再用反斜线将需要转义的字符转义。
正则表达式的格式
在Unix 中,正则表达式是被包含在一对斜线中的,斜线之间包含要匹配的字符(模式)。下面是几个例子:
/piano/ /[Pp]iano/ /*pinfo/ /s\{2,5\}oho/
3 正则表达式实例解析
下面我们就以具体的实例来看一下如何使用正则表达式。其中用黑体着重标出的是匹配到的字符串。
一个最简单的例子便是 /all/,比如下面一段文字:
John’s ball fell into the hole
John cried because it is all his life.
这个正则表达式不含任何的原字符,它查找的是字符串all,这个字符串all可以是独成一个单词,也可以是其它单词的一部分,因此正则表达式/all/既匹配ball里的all,也匹配完整的单词all。
下面我们着重讨论正则表达式里原字符的用法。
3.1 行首、行尾定位符
行首定位符^
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/^Bobby/
匹配位于行首的Bobby。
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/Bobby$/
匹配位于行尾的Bobby。
3.2 词首、词尾定位符
词首定位符 \<
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/\<Bo/
匹配位于词首的字符串Bo。
词尾定位符 \>
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby
Bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/ball\>/
匹配位于词尾的字符串ball。
在一个表达式中搭配使用词首定位符与词尾定位符
John’s ball fell into the hole
John cried because it is his whole life
/\<hole\>/
匹配以h作为单词开头并且以e作为单词结尾的模式hole。也就是说,字母h的前面是一个分隔单词的字符(比如空格或换行符),字母l的后面也是一个分隔单词的字符。这样,在这个例子中只有完整的单词hole会被匹配,而单词whole就不会被匹配。
3.3 匹配单个字符
匹配任意的一个字符 .
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/B…y/
匹配B开头后面紧跟三个任意字符,最后紧接着一个y的字符串。在这个例子中,Bobby和Bippy都会被匹配。
匹配0个或多个前一字符 *
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck balll
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/ al*/
这里的星号(*)匹配0个或多个在它前面的那个字符。前面曾提到过,正则表达式里的*和shell里的*作用是截然不同的。在shell里*表示任意个数的任意字符,而在正则表达式里,*只代表任意个数(包括0个)的前一字符,*可以看作和它前面那个字符是粘连在一起的,*只限制它前面那一个字符。这个正则表达式中的*匹配单独一个或多个连续的l,甚至也匹配一个l也没有的模式,所以,单个字符a也会被匹配。
3.4 匹配多个字符
匹配一组字符里的任意字符 [ ]
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck balll
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/[bw]all/
方括号匹配一组字符中的一个,这个正则表达式查找的是第一个字母是b或w,后面紧跟着all的字符串,因此在这个例子中,wall和ball都会被匹配。
匹配指定范围内的字符 [x-y]
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/B[a-z]p/
方括号里的短线(-)匹配某一范围内的一个字符,这个正则表达式将查找第一个字母是B,第二个字母是ASCII码介于a到z的字符(小写字母),第三个字母是p的字符串。
匹配不在指定范围内的字符 [^ ]
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/all[^A-Z0-9]/
方括号内的脱字符^是一个否定字符,这个正则表达式查找的是后面带一个特殊字符的all,这个特殊字符既不是小写字母又不是大写字母,也不是0到9的数字,比如它可以是一个标点符号或空格。
根据字符x出现的次数匹配 x\{m\} x\{m,\} x\{m, n\}
比如这个正则表达式:/Go\{2,5\}gle/将匹配G后面至少出现2个,最多有不超过5个o的模式。Google,Goooogle会被匹配,而Gogle和Goooooogle则不会被匹配。
3.5 转义字符
如果要匹配的字符串中含有正则表达式的原字符,需要用斜线将其转义,就像c语言里打印单引号 ’ 要写成 \’ 一样。这里有个例子:我们想要查找字符串google.com,要查找的字符串里含有正则表达式的原字符“.”,因此这个正则表达式要写成 /google\.com/,如果不用 \转义,找到的将是google后面跟一个任意的字符,然后跟一个com的字符串。这显然不一定是我们要找的。
3.6 字符标签
例如在下面一段文字里:
Occurence and happening are the most general. I mean, the words occurence and happening are most generally used.
在这段文字里有两个拼错的单词,Occurence和occurence,(其实应该是occurrence),我们可以在vi中用下面的表达式将其修改:
:1,$s/\([Oo]ccur\)ence/\1rence/
我们且不管这个vi命令的用法(其实它是一个替换命令,我们在后面介绍sed时还将提到)我们先拿出这个语句中的两个表达式:
/\([Oo]ccur\)ence/
\1rence
其中前一个是一个正则表达式。这个命令用后面的表达式内容替换前面的正则表达式匹配到的内容。vi编辑器将查找单词Occurence和occurence,如果找到,就把圆括号中的内容加上标签(Occur或occur被加上标签),因为这是第一个被标记的模式,所以被称为标签1。这个模式被保存在称为寄存器1的内存寄存器中。在第二个正则表达式中用\1引用寄存器1中的内容,\1被替换为寄存器中的内容,后面紧跟一个rence,于是,拼错的Occurence和occurence被改正为正确的Occurrence和occurrence。
3.7 原字符组合使用的例子
例1:/\<Bob.*all\>/
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/\<Bob.*all\>/
匹配以Bob开头,后面跟任意个数的任意字符,然后以all结尾的字符串。这里再次重复, *在Shell里表示任意个数的任意字符,而在正则表达式里表示任意个数的前一字符。与 . 配合使用表示任意个数(包括零个)的任意字符。实际上,* 也可以表示重复零次或任意次它前面的一组字符,我们称这一组(有时也可能是一个)字符为“原子”。当原子包括多个字符时,这多个字符要用圆括号括起来,并且需要将圆括号转义;当原子只含一个字符时,可以不用圆括号。在这个例子里,. 表示一个任意字符,紧跟着一个*表示重复0次或任意次前面的那个任意字符。而下面的例子
/\(sup\)*info/
则表示匹配在字符串info前有0个或多个sup的字符串,因此 supinfo, info, supsupinfo都会被匹配。
例2:/B[a-z][bp]*y$/
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.
With his bat Bob banged the ball
Banged it bump against the wall
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby
Bad luck ball, Bad luck Bobby, bad luck ball
Now to drown his many troubles
Bobby Bippy's blowing bubbles.
/B[a-z][bp]*y$/
这个正则表达式匹配这样的字符串:开头字符是B,第二个字母是一个小写字母,后面紧跟0个或多个重复的b或p,最后跟一个y,并且这个字符串位于行的末尾。
4 sed原理及sed命令格式
4.1 Sed工作原理
sed是一个非交互式的流编辑器。所谓非交互式,是指使用sed只能在命令行下输入编辑命令来编辑文本,然后在屏幕上查看输出;而所谓流编辑器,是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕(除非取消了屏幕输出又没有显式地使用打印命令),接着读入下一行。整个文件像流水一样被逐行处理然后逐行输出。
下面我们看一下sed的工作过程。
sed不是在原输入上直接进行处理的,而是先将读入的行放到缓冲区中,对缓冲区里的内容进行处理,处理完毕后也不会写回原文件(除非用shell的输出重定向来保存结果),而是直接输出到屏幕上。sed运行过程中维护着两个缓冲区,一个是活动的“模式空间(pattern space)”,另一个是起辅助作用的“暂存缓冲区(holding space)”。一般情况下,每当运行sed,sed首先把第一行装入模式空间,进行处理后输出到屏幕,然后将第二行装入模式空间替换掉模式空间里原来的内容,然后进行处理,以此类推。
插图
一般情况下暂存缓冲区是用不到的,但有特殊的命令可以在模式空间与暂存缓冲区之间交换数据,后文将有介绍。由于sed对文本的所有操作都是在缓冲区里进行的,所以不会对原文件造成任何破坏。
4.2 Sed命令格式
sed的命令格式如下:
sed [-Options] [‘Commands’] filename
其中,Command是一个sed命令,sed命令一定要被包含在一对单引号中,以免被shell解释,其格式如下:
[address-range][sed-command]或
[Pattern-to-match][sed-command]
address-range是指要处理的行的范围,又叫地址范围;pattern-to-match是一个要匹配的模式,是一个正则表达式,sed-command是一个sed命令,用来对指定的行进行处理。下面是一个简单的例子:
sed –n ‘1,3p’ students
这个命令将文件students中的第1到3行打印到屏幕。注意,地址范围和sed命令之间没有空格,如果加入空格,sed也会将其忽略。参数-n用来取消默认输出。默认情况下,sed每读入一行到模式空间,无论是否对其进行处理,在读入下一行之前多要将模式空间中的内容输出到屏幕上。参数-n可以用来取消这种默认的输出,只有当用户用命令p时才将指定的行输出到屏幕。如果没有用参数-n而又对指定行执行了p命令,那么这些行将会被打印两次。
地址范围可以是一个数字,这个数字代表了一个行号;也可以是一个用逗号分隔的两个数字表示的范围(包括这两行)。范围可以是数字,正则表达式,或是两者的组合。
pattern-to-match是一个要匹配的模式,sed将会对所有匹配的行执行sed-command。其实,这里的pattern-to-match也可以看作是一个地址,这个地址是所有与指定模式匹配的行的行号。因此sed的格式可以归纳为一种:
sed [-Options] ‘[address-range][sed-command]’ filename
5 sed命令与选项
5.1 Sed命令
常用的sed命令如下表所列:
命令
功能
a\
在当前行之后插入一行或多行
c\
用新文本替换当前行中的文本,并开始新的一轮sed命令的执行
d
删除行
i\
在当前行之前插入文本
h
将模式空间里的内容拷贝到暂存缓冲区并替换原来暂存缓冲区的内容
H
将模式空间里的内容追加到暂存缓冲区
g
将里暂存缓冲区的内容拷贝到模式空间并替换原来模式空间的内容
G
将暂存缓冲区里的内容追加到模式空间
p
打印模式空间的内容
n
读入下一行到模式空间,并接着从下一条命令开始执行
q
直接退出sed,不继续执行其后的命令
r
读入指定文件的内容
w
将行写入文件
!
对所选行以外的行进行处理
s/regexp/replacement/flag
用replacement替换模式空间由regexp匹配到的内容
x
交换模式空间与暂存缓冲区的内容
y/source-chars/dest-chars/
将source-chars的字符换成对应的的dest-chars中的字符,source-chars和dest-chars中的字符个数要相同。source-chars和dest-chars中都不能有正则表达式。
=
打印当前行的行号,行号是令起一行打印的
#
sed脚本文件中领起注释
替换命令s/regexp/replacement/flag 中的flag:
flag
功能
g
进行全局替换。不使用此选项将只对该行匹配到的第一个结果进行替换
p
打印模式空间中的内容(替换之后的内容)
w filename
将替换之后的内容写入文件filename
在后面的章节“sed实例解析”中我们将以实例的形式详细介绍各个命令的用法。
相关推荐
在IT领域,文本处理是日常工作中不可或缺的一部分,而grep、sed、awk和perl这四个工具在处理文本时都广泛地使用了正则表达式。它们各自有着不同的特性和适用场景,理解它们之间的差异有助于我们更高效地进行文本操作...
"sed 正则表达式详解" sed 是一个功能强大的流编辑器,它可以根据模式来处理文本,下面是 sed 的一些基本概念和使用方法。 sed 基本概念 sed 的工作模式是将输入文本分行处理,每行文本都被存储在模式空间中。在...
正则表达式,又称规则表达式。(英语:Regular ...正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成"regex",单数有regexp、regex,复数有regexps、regexes、regexen。
此外,在日常工作中使用的工具如 grep、sed 和 awk 等也支持正则表达式的操作。 #### 三、基本概念介绍 1. **元字符**:正则表达式中的特殊字符,用于构建复杂的匹配规则。 - **`.`**:匹配任何单个字符(除了换...
在Linux Shell环境中,正则表达式常与grep、sed、awk等命令结合使用,以实现高效的数据筛选和处理。 1. 元字符:正则表达式的核心是元字符,它们具有特殊的含义。例如,`.`表示任意单个字符,`^`表示行首,`$`表示...
在Linux和Unix环境中,正则表达式常用于命令行工具,如grep、sed和awk等。在这些环境中,正则表达式广泛用于文本处理和自动化任务的脚本编写。 综上所述,正则表达式是文本处理中不可或缺的工具。通过理解正则...
awk的模式匹配部分可以是任何正则表达式,而sed的命令中也可以包含正则表达式。例如,用awk替换所有"error"为"success": ```bash awk '{gsub(/error/,"success")}1' file ``` 这里的`gsub`函数全局搜索并替换,`1`...
正则表达式,又称规则表达式。(英语:Regular ...正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成"regex",单数有regexp、regex,复数有regexps、regexes、regexen。
计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。 许多程序设计语言都支持利用正则表达式进行字符串...正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。
正则表达式,又称规则表达式。...正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。
《学习正则表达式》从正则表达式的基本概念讲起,到编写完整的sed和Perl脚本,再到转换HTML文件,将这种强大的工具解释得清晰透彻。书中贯穿了大量简洁明了的示例,旨在让读者轻松掌握正则表达式。此外,书中各在线...
正则表达式(Regular Expression),简称RE,是一种用于文本模式匹配的强大工具,尤其在Unix环境下,它被广泛应用于grep、sed、awk等实用工具中,极大地提升了文本处理的效率和灵活性。本文将深入探讨Unix下的正则...
“正则表达式运用之 sed工具命令.txt”文件介绍了sed命令,这是一个流编辑器,常与正则表达式结合使用。通过sed,我们可以对输入流中的每一行进行模式匹配,并执行替换、删除、打印等操作。例如,`sed 's/pattern/...
例如,Perl和JavaScript的正则表达式支持不同的语法特性,而grep和sed命令在Linux/Unix环境中提供了命令行的正则处理功能。理解这些工具之间的异同,可以帮助你在不同环境下灵活运用正则表达式。 "aspsun....
详细介绍sed awk正则表达式
正则表达式在多种平台上都有应用,包括 Unix 平台下的程序,如 xsh、egrep、sed、vi 等。它们可以被很多语言采纳,如 HTML 和 XML,这些采纳通常只是整个标准的一个子集。 正则表达式的语法看起来很相似,这是因为...