Unix 正则表达式SED - Unix
正则表达式是一个字符串,它可以用来描述几个字符序列。使用正则表达式是由几个不同的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,依此类推。在这里,我用断行运行此命令之前你应该删除。