所在位置:

sed的基本用法

grepsedawk 是文本处理的三剑客。grep 主要是用于文本的搜索,sed 主要用于文本的编辑,awk 主要用于文本的格式化处理。

sedstream editor 的简称,叫做流编辑器。其实 sed 的内容可以写一本书,这一节主要讲一下 sed 的基本概念及用法

sed 基本原理

sed 在处理文本的时候是以 为单位的,如果没有限制范围,sed 会对每一行进行处理。sed 由标准输入读入一行数据放到一个叫做 模式空间 的地方来执行脚本,处理后就会把 模式空间 的结果输出到标准输出,接着重复上述的动作,直到读完所有数据为止。但是有时我们也想对 模式空间 进行操作,这时就需要用到另外一个临时的空间,叫做 暂存空间,有专门的指令来操作个 暂存空间 的。

sed 格式

sed [option...] [script] [inputfile...]

option 的参数

-f 参数

这个 -f 主要是把所有脚本放到文件里去执行,用来指定脚本文件的

sed -f scriptfile [inputfile...]
-e 参数

这个 -e 参数后面要跟执行的命令,如果要执行多条命令,可以使用多个 -e,或者每条命令用 ; 分隔也可以

sed -e 'command_1' -e 'command_2' -e 'command_3' [inputfile...]

或者

sed -e 'command_1;command_2;command_3' [inputfile...]
-n 参数

sed 会自动输出所有的行的,不管有没有匹配,但有时我们不想自动输出,或者我们只想输出匹配的,这时 -n 就非常有用,这个 -n 就可以控制所有的行是否被输出,一般来说, -n 都是跟 p 参数一起用,用来打印匹配的行

-i 参数

如果 -i 后面没有跟后缀,那么 -i 指定要将sed的输出结果保存到当前编辑的文件中,这个选项会生成一个临时文件,处理完所有命令,就会把临时文件覆盖原文件,并把命令替换为原文件名。如果指定了后缀,这个后缀的文件名会保存原文件的内容,原文件会被新的内容覆盖。

其实除了 -i 可以保存结果,也可以用 重定向 来保存执行命令的结果。

sed -i['.txt']  [script] [inputfile...] #  这个 .txt 可以改为任意的后缀
-s 参数

默认情况下,如果有多个输入文件,会把所有文件组合成一个文件来操作,如果想单独操作这些文件,可以使用 -s 参数

sed -s [script] [inputfile...]
-r 参数

我们之前在 grep 里讲过有基础正则表达式和扩展正则表达式,这个 -r 参数,就是使用扩展正则表达来匹配。

sed -r [script] [inputfile...]

script 参数

我们从上面知道 sed -e 'command_1;command_2;command_3' [inputfile...]command_1command_2command_3 就是 script,而这个 command_1 就是由 选址 + 命令 组成的,下面分别来说一下选址和命令参数:

选址

什么叫选址呢?简单来说,就是用某种方式来确定某些行的位置。为什么要选址呢?确定了地址范围就可以用 下面的 script 执行操作。选址大概有三种方式可以实现:

  • 行号:就是一个简单的数字后面加 script命令,例如 1d、5d

  • 数字推导公式:

    a. num1~num2,表示选择 num1 + (n*num2) ,例如: 1~2,表示 选择 1、3、5、7...的奇数行

    b. 选址, +N,这个选址可以是行号、数字推导公式和正则表达式,表示选择匹配 选址的后几行,例如 /test/, +2,表示选中了 test 行再加后面的 2

  • 正则表达式

    a. 关于正则表式的可以看一下之前写的 grep 文章,里面有介绍,sed 的正则跟 grep 的 基本正则表达式是差不多,如果需要使用扩展的正则表式也需要使用 \ 进行转义

    b. 例如:

    1. 1, /^$/ 表示第一行到空白行之间的所有行

    2. 3, 5 表示第三行到第五行之间的所有行

    3. 3, 5! 表示除第三行到第五行之间的所有行

    4. /test1/, /test2/ 表示匹配 test1 到匹配 test2 之间的所有行

    5. 还有很多,这里就不一一说了,有兴趣的可以上网查阅相关资料

script 的各种命令参数

记得要跟上面的 option 参数区分开,下面是一些常用的参数:

  • [address]s/regexp/replace/:表示用 replace 替换 regexp,但每一行只替换一次,如果想每一匹配的行全部替换,可以使用 g,例如: s/abc/test/g,还有可以用 & 来替换 regepx的

  • [address]p:表示打印匹配的行,经常与 option 的 -n 一起使用

  • [address]n:要注意跟 option 的 -n 区分开来,这个是表示下一行

  • [address]d:表示删除

  • [address]i:要注意跟 option 的 -i 区分开来,这个是表示搜索或者其实操作的时候不区分大小写

  • [address]c\要修改的文本:表示修改匹配行的文本

  • [address]i\要插入的文本:表示在匹配行前面插入文本

  • [address]a\要添加的文本:表示在匹配行后面添加文本

  • [address]y/source/dest/:表示把source的每一个字符串都依次替换为 dest 的每一个字符,source 的字串要跟 dest 的字符一样,注意不能加 g,这个是自动全局替换的

  • [address]{command1;command2}:表示可以在花括号里可以执行一组命令

  • q:注意,这个命令的地址部分只能是单行地址而不能用正则表达式。

说明: h H g G X 的内容暂时不说,涉及到 暂存空间模式空间 那块

inputfile 的说明

如果没有给出 inputfile 或者为 -- ,那么输入文本将从标准输入中取得,可以给多个 inputfilesed 将依次从各文件中执行命令

举例

测试文本( test.txt )的内容
The old man was thin and gaunt with deep wrinkles in the back of his neck.
The brown blotches of the benevolent skin cancer the sun
 this is a 135 test 135.
124  56 3433 33
    But none of 3 these scars were fresh.
They were as old as erosions in a fishless desert.

as as as as as    as as deeep


1 one test \abc good ao scars were fresh one 1.
asdf jas df hao-test asdf dsafjdasf
h.ao ais js bin
bash
删除所有空白行
sed -e '/^$/d' test.txt

或者

sed -e '/./!d' test.txt
只显示前三行
sed -e '3q' test.txt

或者

head -3 test.txt
显示最后一行
sed -e '$!d' test.txt

或者

sed -n -e '$p' test.txt

或者

tail -1 test.txt
删除偶数行
sed -e 'n;d' test.txt

或者

sed -e '2~2d' test.txt
把每一行最前面的 空格制表符 删除
sed -e 's/^[ \t]*//' test.txt
只显示包含one这个单词的行
sed -n -e '/\<one\>/p' test.txt

或者

sed -e '/\bone\b/!d' test.txt

或者

grep '\bone\b' test.txt
显示包含 one 的这一行的下一行显示,不包含匹配one这一行
sed -n -e '/one/{n;p;}' test.txt
显示包含 one 的这一行的下一行,并包含匹配one这一行
sed -n -e '/one/, +1p' test.txt
显示以单个数字开头的行
sed -n -e '/^[0-9]/p' test.txt

或者

grep '^[0-9]' test.txt
显示以一个 one 单词的行到最后的行
sed -n -e '/\<one\>/,$p' test.txt
显示3行到6行的所有行
sed -n -e '3,6p' test.txt

或者

sed -e '3,6!d' test.txt
显示包含one的第一行到包含test的最后一行
sed -n -e '/one/, /test/p' test.txt

或者

sed -e '/one/, /test/!d' test.txt
显示包含 old 或者 this 的行
sed -n -e '/old\|this/p' test.txt

或者

grep 'old\|this' test.txt
显示第五行
sed -n -e '5p' test.txt

或者

sed -e '5!d' test.txt

或者

sed -n -e '6q;5p' text.txt # 如果是在一个大型文件,这种效率会更高,因为只显示q行之前的数据
在以包含 of 的行 到包含 were 的行 为范围,全局用 out 替换 in
sed -e '/of/, /were/s/in/out/g' test.txt
删除 所有以 包含 of 的行 到 包含 were 的行
sed -e '/of/, /were/d' test.txt
删除顶部的所有空白行
sed -e '/./, $!d' test.txt
在包含the的行的后面添加一行,并且这一行的内容是 add content
sed -e '/the/a\add content' test.txt
在包含the的事行替换的内容是 add content
sed -e '/the/c\add content' test.txt
把全局的 as 替换为 if,用 test.txt.bak 来备份原来的文件,原来的文件用最新的结果来覆盖
sed -i'.bak' -e 's/as/if/g' test.txt
交换用 - 连接起来的两个单词的位置
sed -e 's/\(\<[a-z]*\>\)\-\(\<[a-z]*\>\)/\2\-\1/g' test.txt
递归搜索一个目录的所有子目录,找出匹配 good 的行
find . -type f -exec sed -n -e '/good/p' {} \;

或者

find . -type f | xargs sed -n -e '/good/p'

或者

find . -type f -exec grep 'good' {} \;

或者

find . -type f | xargs grep 'good'
打印 test 目录下所有以 .txt 结尾的文件的第三行
find test -name "*.txt" | xargs sed -s -n -e '3p'

或者

find . -name "*.txt" -exec sed -s -n -e '2p' {} \;
给 test 目录的所有以 .txt 结尾的文件的第三到第十行前面添加 # 注释
find . -maxdepth 1 -name "*.txt" | xargs sed -s -e '3,10s/^/# /g'

或者

find . -maxdepth 1 -name "*.txt" -exec sed -s -e '3,10s/^/# /g' {} \;

【上一篇】Linux下grep命令的12个例子【翻译】

【下一篇】15个有用的sed命令技巧应用于日常Linux系统管理任务【翻译】