简介
shell脚本语言包含了众多用于解决Unix/Linux系统问题的工具,其中有不少和文本处理相关,包括sed、awk、grep(awk和grep命令已经在前面的文章中进行了说明),这些工具可以相互结合以满足文本处理需求。
正则表达式是一种基础的模式匹配技术。大多数文本处理工具都支持正则表达式,我们可以对文本文件执行过滤、剥离(strip)、替换、搜索等操作。
目录
示例6:子串匹配标记。可以用\1,\2,……表示子模式匹配到的内容。
正则表达式
正则表达式是由字面文本和具有特殊意义的符号组成的。我们可以根据需要,构造出合适的正则表达式来匹配任何文本。要想使用正则表达式需要先了解正则表达式的规则。
1、正则表达式规则
规则1:位置标记锚点。
有时候需要匹配“以xxx开头”或“以xxx结尾”的文本,就需要标记匹配文本的位置。
正则表达式 | 描述 | 示例 |
^ | 匹配以正则表达式的文本开头的字符串 | ^tux能匹配以tux起始的行 |
$ | 匹配以正则表达式的文本结尾的字符串 | tux$能匹配以tux结尾的行 |
规则2:标识符。
标识符是正则表达式的基础组成部分,它定义了匹配特定的文本必须存在(或不存在)的字符。
正则表达式 | 描述 | 示例 |
A(字符的代称) | 正则表达式必须匹配该字符 | A能够匹配A |
. | 匹配任意一个字符 | appl.能够匹配apple和apply,但是不能匹配apples |
[ ] | 匹配中括号内的任意一个字符。中括号内可以是一个字符组或字符范围 | coo[kl]能够匹配cook]和cool,[0-9]匹配任意单个数字 |
[^ ] | 匹配不在中括号内的任意一个字符。中括号内可以是一个字符组或字符范围 | 23[^45]可以匹配236和237,但是不能匹配234和235;A[^0-9]匹配A以及随后的任意非数字单个字符 |
规则3:数量修饰符。
一个标识符可以出现一次、多次或不出现。数量修饰符定义了模式可以出现的次数。
正则表达式 | 描述 | 示例 |
? | 匹配之前的项1次或0次 | colou?r能够匹配color和coloour |
+ | 匹配之前的项1次或多次 | Rollno-9+能够匹配Rollno-9和Rollno-99,但是不能匹配Rollno- |
* | 匹配之前的项0次或多次 | co*l能够匹配cl、col和coool |
{n} | 匹配之前的项n次 | [0-9]{3}能够匹配任意的三位数,[0-9]{3}等价于[0-9][0-9][0-9] |
{n, } | 之前的项至少需要匹配n次 | [0-9]{2,}能够匹配任意一个两位或更多位数字 |
{n,m} | 之前的项最少匹配n次,最多匹配m次 | [0-9]{2,5}能够匹配两位数到五位数之间的任意一个数字 |
规则4:一些其他的符号。
正则表达式 | 描述 | 示例 |
() | 将括号中的内容视为一个整体 | ma(tri)?x可以匹配max和matrix |
| | 指定了一种选择,可以匹配 | 两边的任意一项 | Oct (1st | 2nd)能够匹配Oct 1st或Oct 2nd |
\ | 转义字符,可以转移之前介绍的特殊字符 | a\.b可以匹配a.b,而不是在二者中间匹配任意一个字符 |
2、一些正则表达式含义
熟悉了上面介绍的正则表达式的规则,接下来可以尝试解读一下复杂的正则表达式。
示例1:匹配任意单词的正则表达式
( +[a-zA-Z]+ +)
开头的加号匹配一个或多个空格,[a-zA-Z]用于匹配任意一个大写或小写字母,其后的加号表示至少匹配1个大写或小写字母,最后的加号表示需要匹配一个或多个空格来终结单词。
如果考虑到匹配句子末尾的单词,可以将句子末尾的标点符号放入正则表达式:
( +[a-zA-Z]+[?,.]? +)
[?,.]?匹配问号,逗号或点号中的一个,0次或1次(也就是有或者没有标点符号)。
示例2:匹配IP地址,IP地址是由点号分隔的4组三位数字。
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
#也可以用[[:digit:]]表示数字,写成如下形式:
[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}
注:上面的正则表达式可以匹配文本中的IP地址,但是并不检查地址的合法性。
示例3:匹配电子邮件地址的正则表达式。
[a-zA-Z0-9._]+@[a-zA-Z0-9.]+\.[a-zA-Z]{2,4}
电子邮件的地址采用“name@domain.some_2-4_letter”这种形式命名,[a-zA-Z0-9._]+表示匹配大小写字母、数字、下划线和点号1次或多次,@后的domain“[a-zA-Z0-9.]+”表示匹配大小写字母、数字和点号1次或多次,后面匹配一个点号,用\进行转义,[a-zA-Z]{2,4}能够匹配长度为2、3或4的字符串。
sed命令处理文本
1、sed命令进行文本替换
sed是stream editor(流编辑器)的缩写。它最常见的用法是进行文本替换。
示例1:在文本中对特定的匹配模式进行字符串替换。
$ sed 's/pattern/replace_string/' file
其中pattern可以是简单的字符串或正则表达式,需要注意的是,正则表达式中“\d”表示一个十进制数,但在sed命令里,必须用[0-9]来表示,正则表达式中的“+”和“?”,在sed命令中也要加上反斜杠即:“\+”和“\?”。
例如:将file.txt文件中的text替换为test.
$ sed 's/text/test/' file.txt
示例2:在文本中对特定的匹配模式进行字符串的全局替换。
上面的命令只替换每行中第一次出现的text,如果想将文本中所有text全部替换,需要使用g标记,具体如下:
$ sed 's/text/test/g' file.txt
g标记可以使sed替换第N次出现的匹配:
$ echo thisthisthisthis | sed 's/this/THIS/2g'
结果:从每行的第2个开始进行替换
$ echo -e "thisthisthisthis\nthisthisthisthis" | sed 's/this/THIS/3g'
结果:从每行的第3个开始进行替换
$ echo -e "thisthisthisthis\nthisthisthisthis" | sed 's/this/THIS/4g'
结果:从每行的第4个开始进行替换
示例3:选项-i会使得sed用修改后的数据替换原始文件。
例如 :file.txt文件的内容如下:
This is a text.The text is a special thing.First,we need install make and gcc.
second,the text also need to install package.
$ sed 's/text/test/g' file.txt
使用这一命令的结果为:将文本中所有text替换为test
但是file.txt文件中的内容并没有修改, 加入-i参数后,则可修改原文的内容,
示例4:更改分隔符。
上面的sed命令中,s之后的/字符被视为命令分隔符,这是默认的,我们也可以使用其他分隔符,例如:
$ sed 's:text:test:g' file.txt
#或
$ sed 's|text|test|g' file.txt
示例5:已匹配的字符串的标记,使用“&”这一符号标记。
在sed中,我们可以用&指代模式所匹配到的字符串,这样就能在替换字符串时使用已匹配的内容。例如:
$ echo this is an example | sed 's/\w\+/[&]/g'
该命令是将这一文本中每一个单词用中括号括起来。\w也是常用的正则表达式符号,用于匹配大小写字母、数字或下划线,“+”表示匹配之前的项1次或多次,在sed命令中要使用”\+“(加上反斜杠),匹配到单词后,用“[&]”替换它,“&”对应匹配到的单词。
结果:
示例6:子串匹配标记。可以用\1,\2,……表示子模式匹配到的内容。
在sed命令中,放在括号中的部分正则表达式表示子模式,也就是用这部分正则表达式匹配子串。例如:
$ echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
该命令是将“digit 7”替换为“7”.其中\(pattern\)用于匹配子串(子模式放入使用反斜杠转义过的括号中),本例中 \([0-9]\)匹配到的子串是7.匹配到的第一个子串,对应标记是\1,匹配到的第二个子串标记是\2,以此类推。
结果:
例如:
$ echo seven EIGHT | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
“\([a-z]\+\)”用于匹配小写字母的单词,匹配结果标记为\1,“\([A-Z]\+\)”用于匹配大写字母的单词,匹配结果标记为\2,匹配完成后,替换时“\2 \1”相当于将第一个和第二个匹配结果换序了。
结果:
示例7:在sed命令中使用变量,双引号就派上用场了。
例如:
$ text=hello
$ echo hello world | sed "s/$text/HELLO/"
结果:
2、sed命令在文本中添加一行或删除一行
编辑命令 | 含义 |
d | 删除文本中特定的行 |
a | 在指定行后增加一个新行,新增行的内容是"a"后面带的文本 |
i | 在指定行前增加一个新行,新增行的内容是"i"后面带的文本 |
示例1:使用“d”移除文件中的特定行
$ sed '/pattern/d' file #删除file中pattern匹配到的行
$ sed '2d' file #删除file文本中的第二行,也可以换成其他数字
$ sed '1,4d' file #删除file文本中的第一行到第四行(包含第一行和第四行)
$ sed '$d' file #删除file中的最后一行
例如:
test.txt 内容如下:
This is a test.The test is a special thing.
First,we need install make and gcc.
second,the test also need to install package.
third, we need other preparations.for example,the version of os should be 3.2.
①删除test.txt中包含“test”的行
$ sed '/test/d' test.txt
结果: 删除了包含test看的行,但是并没有更改原文件的内容,如需更改,需要加上-i选项。
②删除test.txt中的空行。
$ sed '/^$/d' test.txt #删除文本中的空行
空行可以用正则表达式“^$”匹配,/d告诉sed不执行替换操作,而是直接删除匹配到的空行。
结果:
示例2:使用“a”在文本指定行后面添加一行。
$ sed '2a\This is a sample.' file #在file的第二行后面添加一行,内容为"This is a sample."
$ sed '$a\This is a sample.' file #在file文本最后添加一行,内容为"This is a sample."
例如:
$ sed '3a\this is a sample.' test.txt #在第三行后添加一行
$ sed '$a\this is a sample.' test.txt #在最后一行后添加一行
示例3:使用“i”在文本指定行前面添加一行。
$ sed '2i\hello world.' file #在file的第二行前面添加一行,内容为"hello world."
$ sed '$i\hello world.' file #在file文本最后一行前面添加一行,内容为"hello world."
例如:
$ sed '2i\hello world.' test.txt
结果:
$ sed '$i\hello world.' test.txt
结果: