shell sed命令详解
文章目录
正则表达式是一个字符串,可用于描述多个字符序列。正则表达式可用于几种不同的Unix命令,包括ed、sed、awk、grep,以及更加强大的的vim。
这里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的一般语法-
/pattern/action
在这里,pattern是一个正则表达式,而action是下表中给出的命令之一。如果省略了pattern,则如上所述,将对每一行执行操作。
包围花样的斜杠(/)是必需的,因为它们用作分隔符。
Sr.No. | Range & Description |
---|---|
1 | p 打印行 |
2 | d 删除行 |
3 | s/pattern1/pattern2/ 用pattern替换pattern1 |
用sed删除所有行
现在我们将了解如何使用sed删除所有行。再次调用sed;但是sed现在应该使用命令delete line,用一个字母d−表示
$ cat /etc/passwd | sed 'd'
可以指示sed而不是通过通过管道向其发送文件来调用sed,如以下示例所示。
以下命令与上一个示例完全相同,但没有cat命令-
$ sed -e 'd' /etc/passwd
$
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
请注意,数字1已添加到delete edit命令之前。这指示sed在文件的第一行执行编辑命令。在此示例中,sed将删除/ etc / password的第一行并打印文件的其余部分。
sed多行
现在,我们将了解如何使用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
上面的命令将应用于从1到5的所有行。这将删除前五行。
Sr.No. | Range & Description |
---|---|
1 | ‘4,10d’从第4行到第10行被删除 |
2 | ‘10,4d’只删除了第10行,因为sed没有反向工作 |
3 | ‘4,+5d’这将匹配文件中的第4行,删除该行,继续删除后面的5行,然后停止删除并打印其余的行 |
4 | ‘2,5!d’这将删除除第2行到第5行之外的所有内容 |
5 | ‘1~3d’这将删除第一行,执行接下来的三行操作,然后删除第四行。Sed继续应用此模式,直到文件结束。 |
6 | ‘2~2d’这告诉sed删除第二行,跨下一行,删除下一行,并重复,直到到达文件的末尾 |
7 | ‘4,10p’打印从4号到10号的行 |
8 | ‘4,d’这会产生语法错误 |
9 | ‘,10d’这也会产生语法错误 |
注意:在使用p操作时,应该使用-n选项,以避免重复行打印。检查以下两个命令之间的区别-
$ cat /etc/passwd | sed -n '1,3p'
Check the above command without -n as follows −
$ cat /etc/passwd | sed '1,3p'
替换命令
用s表示的substitution命令将用指定的其他字符串替换指定的任何字符串。
要用一个字符串替换另一个字符串,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标志之外,还可以传递许多其他有用的标志,并且您一次可以指定多个。
Sr.No. | Flag & Description |
---|---|
1 | g替换所有匹配项,而不仅仅是第一个匹配项 |
2 | NUMBER只替换指定行匹配 |
3 | p如果进行了替换,则打印模式空间 |
4 | w FILENAME如果进行了替换,则将结果写入文件名 |
5 | I or i以不区分大小写的方式匹配 |
6 | M or m除了特殊的正则表达式字符^和的正常行为之外,这个标志还会使^匹配换行符后的空字符串和换行符前的空字符串 |
设置分隔符字符串
假设您必须对包含正斜杠字符的字符串进行替换。在这种情况下,可以通过在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文件中完全删除根字符串-
$ cat /etc/passwd | sed 's/root//g'
:x:0:0::/:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
字符替换
如果只想在第10行将字符串sh替换为quiet的字符串,则可以如下指定它:
$ 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
同样,要进行地址范围替换,您可以执行以下操作-
$ 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
从输出中可以看到,前五行的字符串sh更改为quiet,但其余各行保持不变。
匹配命令
您将使用p选项和-n选项一起打印所有匹配的行,如下所示:
$ 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
使用正则表达式
在匹配模式时,您可以使用正则表达式来提供更大的灵活性。
检查以下示例,该示例匹配以_daemon_开头的所有行,然后将其删除-
$ 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
以下是删除所有以sh结尾的行的示例-
$ cat testing | sed '/sh$/d'
sync:x:4:65534:sync:/bin:/bin/sync
下表列出了四个在正则表达式中非常有用的特殊字符。
Sr.No. | Character & Description |
---|---|
1 | ^匹配开始 |
2 | $匹配结束 |
3 | . 匹配任意字符 |
4 | ***** 匹配0次或者多次 |
5 | [chars]匹配以字符形式给出的任何字符,其中字符是字符序列。可以使用-字符表示字符范围。 |
匹配字符
再看几个表达式来演示元字符的使用。例如,下面的模式-
Sr.No. | Expression & Description |
---|---|
1 | /a.c/匹配包含字符串的行,如a+c、a-c、abc、match和a3c |
2 | /a*c/将相同的字符串与字符串(如ace、yacc和arctic)匹配 |
3 | /[tT]he/匹配字符串和 |
4 | /^$/匹配空行 |
5 | */^.\$/匹配整个行,不管它是什么 |
6 | / */匹配一个或多个空格 |
7 | /^$/匹配空行 |
下表显示了一些常用的组:
Sr.No. | Set & Description |
---|---|
1 | [a-z]匹配一个小写字母 |
2 | [A-Z]匹配一个大写字母 |
3 | [a-zA-Z]匹配一个字母 |
4 | [0-9]匹配单个数字 |
5 | [a-zA-Z0-9]匹配单个字母或数字 |
字符类关键字
正则表达式通常可以使用一些特殊的关键字,尤其是采用正则表达式的 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中可用字符类关键字的完整列表。
Sr.No. | Character Class & Description |
---|---|
1 | [[:alnum:]]Alphanumeric [a-z A-Z 0-9] |
2 | [[:alpha:]]Alphabetic [a-z A-Z] |
3 | [[:blank:]]Blank characters (spaces or tabs) |
4 | [[:cntrl:]]Control characters |
5 | [[:digit:]]Numbers [0-9] |
6 | [[:graph:]]Any visible characters (excludes whitespace) |
7 | [[:lower:]]Lowercase letters [a-z] |
8 | [[:print:]]Printable characters (non-control characters) |
9 | [[:punct:]]Punctuation characters |
10 | [[:space:]]Whitespace |
11 | [[:upper:]]Uppercase letters [A-Z] |
12 | [[: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
在模式部分中,您要匹配前3位数字,然后使用&将3位数字替换为周围的括号。
使用多个sed命令
您可以在单个sed命令中使用多个sed命令,如下所示-
$ sed -e 'command1' -e 'command2' ... -e 'commandN' files
在这里,command1到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
注意 -在上面的示例中,我们没有用\ {3 \}替换字符类关键字[[:digit:]]三次,而是将其替换为\ {3 \},这意味着前面的正则表达式被匹配了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
注 –在上面的示例中,括号内的每个正则表达式都将被\ 1,\ 2等反向引用。我们在这里使用\来换行。在运行命令之前,应将其删除。