前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux三大剑客之sed

Linux三大剑客之sed

作者头像
耕耘实录
发布2018-12-20 12:17:42
8270
发布2018-12-20 12:17:42
举报
文章被收录于专栏:耕耘实录耕耘实录

版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转载请注明出处,谢谢。联系本人:ecsboy(微信),136625317(QQ) https://cloud.tencent.com/developer/article/1375012

一、简介

sed英文全称是stream editor。由贝尔实验室开发,如今主流Unix/Linux操作系统上都集成了这个工具。sed由自由软件基金组织(FSF)开发和维护,并且随着GNU/Linux进行分发,通常它也称作 GNU sed。本文将按照GUN官方在线手册的内容对sed进行介绍。

二、获取帮助信息
[sed@GeekDevOps ~]$ sed --help
[sed@GeekDevOps ~]$ man sed

我们可以通过以上2种方式获取关于sed的帮助信息,也可以通过GUN网站sed在线帮助页面获取更加详细的帮助信息(https://www.gnu.org/software/sed/manual/sed.html

三、sed的使用
3.1 综述

sed遵循简单的工作流:读取(从输入中读取某一行),执行(在某一行上执行sed命令)和显示(把结果显示在输出中)。通常sed命令这样被调用:

sed SCRIPT INPUTFILE...

例如,把文件input.txt中出现的“hello”全部替换为“world”并输出到文件output.txt中:

[sed@GeekDevOps ~]$ echo "hello world">input.txt
[sed@GeekDevOps ~]$ sed "s/hello/world/" input.txt >output.txt
[sed@GeekDevOps ~]$ cat output.txt 
world world

如果你没有指定输入文件或输入文件是“-”,sed获取到是是标准出入流的内容,以下命令是等价的:

sed 's/hello/world/' input.txt > output.txt
sed 's/hello/world/' < input.txt > output.txt
cat input.txt | sed 's/hello/world/' - > output.txt

sed把输出写到标准输出中,使用选项-i可以编辑原文件并将替换结果打印到标准输出。把输出写入到其他文件中我们也可以参阅W和s///w命令。以下命令修改了文件且不产生任何输出。

[sed@GeekDevOps ~]$ sed -i "s/hello/world/" input.txt 
[sed@GeekDevOps ~]$ cat input.txt 
world world

默认情况下sed打印所有处理过的输出(除非输入已经被诸如d之类的命令修改或删除)。使用选项-n可以不输出除指定内容之外的打印,使用p命令可以打印指定行。以下命令将只打印输入文件的第5行:

[sed@GeekDevOps ~]$ sed -n "5p" /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sed以一个长流的方式处理多个输入文件。以下例子只打印第一个文件的第一行及最后一个文件的最后一行,其实也可以理解成sed把三个文件当做一个文件来处理了,依次追加到第一个文件的后面。也可以用选项-s来逆转这种操作,即把每个文件分开来处理。

[sed@GeekDevOps ~]$ sed -n '2p;$p' /etc/selinux/config /etc/aliases /etc/passwd
# This file controls the state of SELinux on the system.
sed:x:1000:1000::/home/sed:/bin/bash
[sed@GeekDevOps ~]$ sed -ns '2p;$p' /etc/selinux/config /etc/aliases /etc/passwd
# This file controls the state of SELinux on the system.
SELINUXTYPE=targeted 
#  Aliases in this file will NOT be expanded in the header from
#root:      marc
bin:x:1:1:bin:/bin:/sbin/nologin
sed:x:1000:1000::/home/sed:/bin/bash

sed -n -s 与sed -ns这两种写法在本质上是一样的。

不加选项-e(脚本,–expression=脚本)或-f(–file,脚本文件),sed使用第一个非选项参数作为脚本,下面的例子中就是以非选项参数作为输入文件。如果选项-e或-f 被用于指定脚本,那么所有的非选项参数被当作输入文件。选项-e和-f可以联合使用,能出现多次(所有的单个的脚本将被连接起来成为最终有效的实例)。

[sed@GeekDevOps ~]$ echo "hello world">input.txt 
[sed@GeekDevOps ~]$ sed 's/hello/world/' input.txt >output.txt
[sed@GeekDevOps ~]$ cat output.txt 
world world
[sed@GeekDevOps ~]$ sed -e 's/hello/world/' input.txt >output.txt
[sed@GeekDevOps ~]$ sed --expression='s/hello/world/' input.txt > output.txt
[sed@GeekDevOps ~]$ cat output.txt 
world world
[sed@GeekDevOps ~]$ echo 's/hello/world/' > myscript.sed
[sed@GeekDevOps ~]$ cat myscript.sed 
s/hello/world/
[sed@GeekDevOps ~]$ sed -f myscript.sed input.txt >output.txt 
[sed@GeekDevOps ~]$ cat output.txt 
world world
[sed@GeekDevOps ~]$ sed --file=myscript.sed input.txt > output.txt
[sed@GeekDevOps ~]$ cat output.txt 
world world
3.2 命令行选项

完整格式调用sed:

sed OPTIONS... [SCRIPT] [INPUTFILE...]

sed可能被以下命令行选项调用:

–version:打印版本信息。

–help:打印简要帮助信息并退出。

-n、–quiet、–silent:只输出明确处理过的内容。

-e script 、–expression=script:指定脚本。

-f script-file、–file=script-file:指定脚本文件。

-iSUFFIX、–in-place=SUFFIX:在原文件上修改并取代原文件。这一选项暗含-s。

-l N、–line-length=N:指定“l”命令的换行期望长度。长度为0则意味着不含长换行。如果不指定,则换行长度为70。

–posix:GUN sed包含了几个扩展POSIX sed。为了简化书写这些便携脚本,这个选项禁用了这个手册所有的扩展以及附加命令。扩展中被POSIX执行的外部语法大部分接受sed程序,但是以上这些中的一些(例如在报告bug中的N命令描述的行为)事实上违反了标准。如果你需要禁用后期的扩展,你可以设置POSIXLY_CORRECT 变量为以非空值。

-b、–binary:这个选项在每个平台都是可用的,仅仅在操作系统中区分文本文件与二进制文件起到作用。

–follow-symlinks:这个选项仅在支持符号连接且对选项-i被指定有影响的情况下可用。在这种情况下,如果被指定文件在命令行中是一个符号连接,sed将跟随连接并编辑连接的最终目标文件。默认行为是中断符号连接,因此连接目标将不被修改。

-E、-r:扩展正则表达式。

-s、–separate:在上文中已经举过例子,当处理多个输入文件,一般会被合并成一个文件来处理。使用这个选项则可以让sed把各个文件分开单独处理。

–sandbox:沙盒,在沙盒模式,e/w/r命令被拒绝-如果程序包含它们则还没运行时它们将丢弃。沙盒模式确保了sed在输入文件上的操作运行在指定的命令行上,而不能运行在外部命令上。

-u、–unbuffered:从输入文件读取最少的数据,更频繁的刷新输出。这将特别有用,特别像在tail -f这种情况下,能够让我们尽快地看出输出结果。

-z、–null-data、–zero-terminated:把输出看作一个一个被0字节(如:ASCII中的“NULL”)的中断符代替换行的集合。这个选项常和“sort -z”和“find -print0”一起使用。

3.3退出状态

0:成功结束。

1:无效命令、无效语法、无效正则表达式、无效的带–posix的sed扩展命令

2:一个或多个被指定的输入文件不能在命令行中被打开。

4:I/O错误或运行时一个严重进程错误,GUN sed 被立即终止。

四、sed脚本
4.1 sed脚本综述

sed命令遵循以下语法:

addrXoptions

X是一个单个字母sed命令。addr是一个可选的行地址。如果addr是被指定的,那么命令X在匹配的行将被执行。addr可以使用一个单独的行号、正则表达式、或行的范围。附加options被用于一些sed命令。

以下例子删除了GeekDevOps.txt的第3到5行,3,5是一个地址范围,d是删除命令:

[sed@GeekDevOps ~]$ sed "3,5d" GeekDevOps.txt >GeekDevOps.txt.new
[sed@GeekDevOps ~]$ diff GeekDevOps.txt GeekDevOps.txt.new
3,5d2
<         user_input = raw_input("Enter a positive integer to guess: ")
<         if len(user_input)==0 or not user_input.isdigit():
<             print "Not a positive integer!"

以下例子将打印所有以”def”开头的行后退出,退出代码为42,如果没有查找到或者遇到其他错误,退出状态代码将为0(为了节约篇幅,不举例),/^def是一个正则表达式地址,q是退出命令,42是命令选项:

[sed@GeekDevOps ~]$ sed "/^def/q42" GeekDevOps.txt
def guess_my_number(n):
[sed@GeekDevOps ~]$ echo $?
42

多个脚本或脚本文件可以使用选项-e或-f分别指定,如不分别指定的话应该以分号。

[sed@GeekDevOps ~]$ sed -e 's/while/do/;/^def/d' GeekDevOps.txt>GeekDevOps.txt.new
[sed@GeekDevOps ~]$ cat GeekDevOps.txt.new
    do True:
        user_input = raw_input("Enter a positive integer to guess: ")
    ...
[sed@GeekDevOps ~]$ sed -e "s/while/for/" -e '/^def/d' GeekDevOps.txt>GeekDevOps.txt.new
[sed@GeekDevOps ~]$ cat GeekDevOps.txt.new
    for True:
...
[sed@GeekDevOps ~]$ echo "s/while/do_for/">test.sed
[sed@GeekDevOps ~]$ sed -f test.sed -e '/^def/d' GeekDevOps.txt>GeekDevOps.txt.new
[sed@GeekDevOps ~]$ cat GeekDevOps.txt.new
    do_for True:
...

命令a,c,i由于他们的语法原因,不能以分号作为命令分隔符。

4.2 sed命令概述

以下命令在GUN sed是被支持的。一些是标准的POSIX命令,其他的是GUN扩展命令。(此部分原文内容较多,不一一介绍,截取常用部分进行介绍)

a\

文本

在一行后面追加文本。

a 文本

在一行后面追加文本(选择性语法)。

b label

分支无条件标签。在下一个循环开始时可能被省略。

c\

文本

在原位置替换。

c 文本

在原位置替换(选择性语法)。

d

删除模式空间,立即开始下一循环。

i\

文本

在某行之前插入。

i 文本

在某行之前插入(选择性语法)。 

qexit-code

没有任何需要处理的命令或输出退出sed。
(quit) Exit sed without processing any more commands or input.

Qexit-code

类似于q,但是不打印模式空间的内容。具体我们看一下以下例子:
[sed@GeekDevOps ~]$ sed -e '/^def/q23' GeekDevOps.txt
def
[sed@GeekDevOps ~]$ echo $?
23
[sed@GeekDevOps ~]$ sed -e '/^def/Q23' GeekDevOps.txt
[sed@GeekDevOps ~]$ echo $?
23

退出代码都一样,区别就是q有打印输出,Q没有输出。

五、用法举例
5.1
[sed@GeekDevOps ~]$ seq 6|sed '1d
> 2d
> 5d'
3
4
6

等价于:

[sed@GeekDevOps ~]$ seq 6|sed '1d;3d;5d;'
2
4
6

在命令行中,所有的sed命令通过换行来指定,也可以通过分号来指定。

5.2
[sed@GeekDevOps ~]$ seq 4 | sed '{1d;3d}'
2
4
[sed@GeekDevOps ~]$ seq 6|sed '{1d;3d};5d'
2
4
6
[sed@GeekDevOps ~]$ seq 6|sed '{1,3d};5d'
4
6

命令{},b,t,T,: 等是可以被分号隔开的。

5.3

替换指定行的内容。以下例子将在第5行中把hired替换成success:

[sed@GeekDevOps ~]$ sed '5s/hired/success/' GeekDevOps.txt | nl
     1  My father was a self-taught mandolin player. He was one of the best string instrument players in our town. He could not read
     2  music, but if he heard a tune a few times, he could play it. When he was younger, he was a member of a small country music band.
     3  They would play at local dances and on a few occasions would play for the local radio station. He often told us how he had
     4  auditioned and earned a position in a band that featured Patsy Cline as their lead singer. He told the family that after he was
     5  success he never went back. 

以下例子中,把包含music的行中的play替换成enjoy。

[sed@GeekDevOps ~]$ sed '/music/s/play/enjoy/' GeekDevOps.txt |nl
     1  My father was a self-taught mandolin player. He was one of the best string instrument players in our town. He could not read
     2  music, but if he heard a tune a few times, he could enjoy it. When he was younger, he was a member of a small country music band.
     3  They would play at local dances and on a few occasions would play for the local radio station. He often told us how he had

以下例子中,把1-3行中的he全部替换成one,如果后面不加g,则只替换第一个匹配的。

[sed@GeekDevOps ~]$ sed "1,3s/he/one/g" GeekDevOps.txt
My fatoner was a self-taught mandolin player. He was one of tone best string instrument players in our town. He could not read
music, but if one oneard a tune a few times, one could play it. Wonen one was younger, one was a member of a small country music band.
Toney would play at local dances and on a few occasions would play for tone local radio station. 

不含指定部分才进行匹配替换。以下例子中把不含单词apple的行中的hello替换成Hello,感叹号“!”取反,指定行的范围也是一样的操作。

[sed@GeekDevOps ~]$ sed '/apple/!s/hello/Hello/' test.txt
Hello world!This is my apple.Don't touch it.
hello world!This is my apple.Don't touch it.
Hello world!This is my food.Don't touch it.
5.4

sed也是支持正则表达式的。以下例子匹配了/etc/passwd文件中以bash结尾的行。

[sed@GeekDevOps ~]$ sed -n '/bash$/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
sed:x:1000:1000::/home/sed:/bin/bash

以下三种写法都是等价的,只是分隔符不一样而已,如果正则表达式或分隔符本身就包含斜杠的话,那么是需要进行转义处理的。

[sed@GeekDevOps ~]$ sed -n '/^\/home\/GeekDevOps/p' test.txt
/home/GeekDevOps
[sed@GeekDevOps ~]$ sed -n '\;^/home/GeekDevOps;p' test.txt
/home/GeekDevOps
[sed@GeekDevOps ~]$ sed -n '\%^/home/GeekDevOps%p' test.txt
/home/GeekDevOps

地址也可以用范围来表示,例如:

[sed@GeekDevOps ~]$ nl test.txt |sed -n '2,+1p'
2  hello world!This is my apple.Don't touch it.
3  hello world!This is my food.Don't touch it.

接下来再看一个扩展正则表达式的例子。本例中匹配到的是标准输出流中的单词,把每个单词中的字符全部替换成X。如果表达式中的X换成XY的话,那么会将标准输出流中的每个字符换成XY。

[sed@GeekDevOps ~]$ echo 'GeekDevOps is a very useful media !' |sed 's/\w/X/g'
XXXXXXXXXX XX X XXXX XXXXXX XXXXX !

下面的例子中,会在每个单词的前面添加一个“#”,如果需要在每个单词的后面添加内容,那么表达式应为:>

[sed@GeekDevOps ~]$ echo 'GeekDevOps is a very useful media !' |sed 's/\</#/g'
#GeekDevOps #is #a #very #useful #media !
[sed@GeekDevOps ~]$ echo 'GeekDevOps is a very useful media !' |sed 's/\</\#/g'
#GeekDevOps #is #a #very #useful #media !

关于sed的介绍就到此为止吧,!写了许多,感觉自己都搞得晕乎乎的,掌握以上内容一般的文档处理应该是没有问题了!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年02月11日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、简介
  • 二、获取帮助信息
  • 三、sed的使用
    • 3.1 综述
      • 3.2 命令行选项
        • 3.3退出状态
        • 四、sed脚本
          • 4.1 sed脚本综述
            • 4.2 sed命令概述
            • 五、用法举例
              • 5.1
                • 5.2
                  • 5.3
                    • 5.4
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档