位置:首页 > 其他技术 > Unix > Unix 正则表达式SED

Unix 正则表达式SED

正则表达式是一个字符串,它可以用来描述几个字符序列。使用正则表达式是由几个不同的Unix命令,包括 ed, sed, awk, grep,并且,在较为有限的程度上扩展 vi.

本在线教程将教你如何使用正则表达式使用 sed.

这里流编辑器sed的代表是面向流的编辑器,它是专门用于执行脚本创建。因此,所有的输入送入通过到stdout,它不会改变输入文件。

调用 sed:

在我们开始之前,让我们确保你有一个本地副本 /etc/passwd 文件的文本文件,用sed。

正如前面提到的,可以调用sed的发送数据通过管道如下:

$ cat /etc/passwd | sed
Usage: sed [OPTION]... {script-other-script} [input-file]...

  -n, --quiet, --silent
                 suppress automatic printing of pattern space
  -e script, --expression=script
...............................

cat命令转储 /etc/passwd文件的内容通过管道进入sed 模式空间sed 。是内部工作模式空间缓冲区,sed使用做其工作。

sed 一般语法:

以下是 sed 的一般语法

/pattern/action

在这里,模式是一个正则表达式,动作是下表中给出的命令之一。如果省略模式,执行操作的每一行,正如我们上面看到的。

斜线字符(/),环绕模式是必需的,因为它们被用来作为分隔符。

Range 描述
p Prints the line
d Deletes the line
s/pattern1/pattern2/ Substitutes the first occurrence of pattern1 with pattern2.

用sed删除所有行:

再次调用sed ,但这个时候告诉sed使用编辑命令删除行,由单字母d表示:

$ cat /etc/passwd | sed 'd'
$

调用sed 发送文件,通过管道,而是可以指示sed来读取数据文件,在下面的例子。

下面的命令做完全一样的东西,以前的尝试,没有 cat 命令:

$ sed -e 'd' /etc/passwd
$

sed 位址:

SED还了解到一种叫做地址。位址是特定的地点,在一个文件或一个特定的编辑命令应适用范围。当sed遇到没有地址,在该文件中的每一行上执行其操作。

以下命令将sed 命令你已经使用了一个基本的地址:

$ cat /etc/passwd | sed '1d' |more
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
$

请注意,数字1之前添加删除编辑命令。这告诉sed执行编辑命令的第一行上的文件。在这个例子中,sed将删除第一行 /etc/password,并打印文件的其余部分。

sed 地址范围:

所以如果你想从文件中删除多个行?用sed,您可以指定一个地址范围如下:

$ cat /etc/passwd | sed '1, 5d' |more
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
$

上面的命令将开始从1至5的所有行。所以,删除前五行。

试试下面的地址范围:

Range 描述
'4,10d' Lines starting from 4th till 10th are deleted
'10,4d' Only 10th line is deleted, because sed does not work in reverse direction.
'4,+5d' This will match line 4 in the file, delete that line, continue to delete the next five lines, and then cease its deletion and print the rest
'2,5!d' This will deleted everything except starting from 2nd till 5th line.
'1~3d' This deletes the first line, steps over the next three lines, and then deletes the fourth line. Sed continues applying this pattern until the end of the file.
'2~2d' This tells sed to delete the second line, step over the next line, delete the next line, and repeat until the end of the file is reached.
'4,10p' Lines starting from 4th till 10th are printed
'4,d' This would generate syntax error.
',10d' This would also generate syntax error.

注:使用p动作时,你应该使用-n选项,以避免重复行式打印。检查以下两条命令之间的区别:

$ cat /etc/passwd | sed -n '1,3p'

检查上面的命令没有-n作为如下:

$ cat /etc/passwd | sed '1,3p'

替换命令:

替换命令,用s表示,将您指定的其他任何字符串中指定的任何字符串代替。

用一个字符串代替另一个,你需要有一些方式告诉sed,你的第一个字符串结束,并开始替换字符串。这是传统上是由两个字符串bookending斜线(/)字符。

首次出现一行字符串根字符串amrood与下面的命令替代。

$ cat /etc/passwd | sed 's/root/amrood/'
amrood:x:0:0:root user:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
..........................

这是非常重要的,需要注意的是替代sed的只有第一次出现的行上。如果字符串根不止一次发生在一行的第一个匹配项将被替换。

告诉sed执行全局替换,添加字母g结束的命令如下:

$ cat /etc/passwd | sed 's/root/amrood/g'
amrood:x:0:0:amrood user:/amrood:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
...........................

替代标志:

还有一些其他有用的g标志除了可以传递的标志,你可以一次指定多个。

标志 描述
g Replace all matches, not just the first match.
NUMBER Replace only NUMBERth match.
p If substitution was made, print pattern space.
w FILENAME If substitution was made, write result to FILENAME.
I or i Match in a case-insensitive manner.
M or m In addition to the normal behavior of the special regular expression characters ^ and $, this flag causes ^ to match the empty string after a newline and $ to match the empty string before a newline.

使用替代字符串分隔符:

您可能会发现自己不得不做一个替换在一个字符串,其中包含斜线字符。在这种情况下,您可以指定不同的分隔,提供指定的字符后的s。

$ cat /etc/passwd | sed 's:/root:/amrood:g'
amrood:x:0:0:amrood user:/amrood:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh

在上面的例子中,我们使用:作为分隔符,而不是斜线(/),因为我们试图搜索/root ,而不是简单的root。

替换空字符:

使用空替换字符串从 /etc/passwd 文件中完全删除root字符串:

$ cat /etc/passwd | sed 's/root//g'
:x:0:0::/:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh

地址替换:

如果你想用quiet 在第10行字符串替换字符串的sh,您可以指定如下: 

$ cat /etc/passwd | sed '10s/sh/quiet/g'
root:x:0:0:root user:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/quiet

同样,做一个地址范围替换,你可以做类似以下内容:

$ cat /etc/passwd | sed '1,5s/sh/quiet/g'
root:x:0:0:root user:/root:/bin/quiet
daemon:x:1:1:daemon:/usr/sbin:/bin/quiet
bin:x:2:2:bin:/bin:/bin/quiet
sys:x:3:3:sys:/dev:/bin/quiet
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh

正如你可以看到从输出前五行字符串的sh改变quiet,但其余各行均保持不变。

匹配的命令:

你会使用-n选项一起使用p选项打印所有匹配的行,如下所示:

$ cat testing | sed -n '/root/p'
root:x:0:0:root user:/root:/bin/sh
[root@ip-72-167-112-17 amrood]# vi testing
root:x:0:0:root user:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh

使用正则表达式:

在匹配模式中,你可以使用正则表达式,它提供了更多的灵活性。

检查下面的例子匹配所有的行开始守护进程,然后删除它们:

$ cat testing | sed '/^daemon/d'
root:x:0:0:root user:/root:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh

下面的例子将删除所有的行以sh结束:

$ cat testing | sed '/sh$/d'
sync:x:4:65534:sync:/bin:/bin/sync

下表列出了四个特殊字符在正则表达式中是非常有用的。

字符 描述
^ Matches the beginning of lines.
$ Matches the end of lines.
. Matches any single character.
* Matches zero or more occurrences of the previous character
[chars] Matches any one of the characters given in chars, where chars is a sequence of characters. You can use the - character to indicate a range of characters.

匹配字符:

看几个表达式元字符演示使用。例如,下面的模式:

表达式 描述
/a.c/ Matches lines that contain strings such as a+c, a-c, abc, match, and a3c, whereas the pattern
/a*c/ Matches the same strings along with strings such as ace, yacc, and arctic.
/[tT]he/ Matches the string The and the:
/^$/ Matches Blank lines
/^.*$/ Matches an entire line whatever it is.
/ */ Matches one or more spaces
/^$/ Matches Blank lines

下表列出了一些常用的字符集:

Set 描述
[a-z] Matches a single lowercase letter
[A-Z] Matches a single uppercase letter
[a-zA-Z] Matches a single letter
[0-9] Matches a single number
[a-zA-Z0-9] Matches a single letter or number

字符类关键词:

一些特殊的关键字是常用的正则表达式,特别是GNU工具,采用正则表达式。这些sed的正则表达式是非常有用的,因为它们简化了的东西,增强可读性。

例如,字符a到z以及A到Z的字符构成的字符的其中一类,具有关键字 [[:alpha:]]

使用字母字符类的关键字,只有那些行在 /etc/syslog.conf 文件,一个字母开始,这个命令打印:

$ cat /etc/syslog.conf | sed -n '/^[[:alpha:]]/p'
authpriv.*                         /var/log/secure
mail.*                             -/var/log/maillog
cron.*                             /var/log/cron
uucp,news.crit                     /var/log/spooler
local7.*                           /var/log/boot.log

下表是GNU sed的可用字符类中的关键字的完整列表。

Character Class 描述
[[:alnum:]] Alphanumeric [a-z A-Z 0-9]
[[:alpha:]] Alphabetic [a-z A-Z]
[[:blank:]] Blank characters (spaces or tabs)
[[:cntrl:]] Control characters
[[:digit:]] Numbers [0-9]
[[:graph:]] Any visible characters (excludes whitespace)
[[:lower:]] Lowercase letters [a-z]
[[:print:]] Printable characters (noncontrol characters)
[[:punct:]] Punctuation characters
[[:space:]] Whitespace
[[:upper:]] Uppercase letters [A-Z]
[[:xdigit:]] Hex digits [0-9 a-f A-F]

与符号引用:

sed 字元代表的模式相匹配的内容。例如,假设你有一个文件名为phone.txt的完整电话号码,如下面的:

5555551212
5555551213
5555551214
6665551215
6665551216
7775551217

你想更容易阅读的括号包围的区域码(前三位)。要做到这一点,你可以使用符号替换字符,像这样:

$ sed -e 's/^[[:digit:]][[:digit:]][[:digit:]]/(&)/g' phone.txt
(555)5551212
(555)5551213
(555)5551214
(666)5551215
(666)5551216
(777)5551217

在模式匹配第3位,然后使用要更换这3个数字与周围的括号。

使用多个sed命令:

您可以使用多个sed命令在一个单一的sed命令如下:

$ sed -e 'command1' -e 'command2' ... -e 'commandN' files

这里命令通过commandN是前面讨论过的类型的sed命令。这些命令被施加到给定的文件的文件列表中的各行。

我们可以使用相同的机制,上面写的电话号码的例子如下:

$ sed -e 's/^[[:digit:]]{3}/(&)/g'  
                      -e 's/)[[:digit:]]{3}/&-/g' phone.txt
(555)555-1212
(555)555-1213
(555)555-1214
(666)555-1215
(666)555-1216
(777)555-1217

注:在上面的例子中,而不是重复字符类关键字 [[:digit:]]三次,取而代之的是{3},这意味着匹配前面的正则表达式三次。在这里,我用 断行运行此命令之前你应该删除。 

返回参考:

符号元字符是有用的,但更为有用的是能够定义特定的区域,在一个正则表达式,这样你就可以替换字符串中引用它们。通过定义一个正则表达式的特定部分,你可以参考那些部分特别提到字符。

要做返回引用,你必须首先定义一个区域,然后参考该区域。要定义一个区域,你插入反斜杠括号,围绕感兴趣区域。环绕反斜杠第一区域,然后引用 1, 2 第二区域,依此类推。

假设phone.txt有以下文字:

(555)555-1212
(555)555-1213
(555)555-1214
(666)555-1215
(666)555-1216
(777)555-1217

现在尝试下面的命令:

$ cat phone.txt | sed 's/(.*))(.*-)(.*$)/Area 
                       code: 1 Second: 2 Third: 3/'
Area code: (555) Second: 555- Third: 1212
Area code: (555) Second: 555- Third: 1213
Area code: (555) Second: 555- Third: 1214
Area code: (666) Second: 555- Third: 1215
Area code: (666) Second: 555- Third: 1216
Area code: (777) Second: 555- Third: 1217

注意:在上面的例子中括号内的每个正则表达式将引用1 2,依此类推。在这里,我用断行运行此命令之前你应该删除。