sed 命令给我的感觉是 Linux 中最复杂的命令之一,难度堪比编程语言中的正则表达式。不过复杂背后带来的是强大的功能。在掌握了它的用法后,相当于是得到了一件在 Linux 系统上处理文本的利器。
sed 命令格式
sed [选项]... {脚本} [输入文件]...
如果没有给出 -e,--expression,-f,或者 --file 选项,第一个非选项参数会被当作 sed 命令的脚本来解释。所有余下的参数是输入文件的名称。如果没有指定输入文件,默认会从标准输入读取内容。
sed 命令示例
光看上面的命令格式可能还不明就里,直接来看例子。假设要把 test.txt 文件中的 abc 小写字母替换为 ABC 大写字母:
sed 's/abc/ABC/' test.txt
上面的命令会输出执行替换后的内容,但还没有真正去修改文件内容,可以当作是命令处理脚本的预览。如果要直接修改文件内容,需要使用 -i 选项:
sed -i 's/abc/ABC/' test.txt
再去看看文件内容,符合条件的文字一定被修改了。命令脚本中的 / 是定界符,除了这个符号,: 也可以拿来做定界符:
sed 's:abc:ABC:' test.txt
除了替换字符,sed 命令还可以用来清理文件中的空白行:
sed '/^$/d' test.txt
删除指定行,比如要删除第 3 行:
sed '2d' test.txt
按行区间来删除,比如从 3 行到最后一行都删除:
sed '2,$d' test.txt
删除以 abc 开头的行:
sed '/^abc/d' test.txt
匹配 abc 并给匹配到的内容加上中括号:
sed 's/abc/[&]/' test.txt
搭配 grep 命令批量替换指定的文件:
sed -i 's/zzx/zzxworld/g' `grep "zzx" -rl --include="*.htm" ./`
sed 命令选项
| 缩写 | 完整名称 | 说明 | 
|---|---|---|
-n | 
--quiet, --silent | 
不自动打印模式空间的内容。 | 
-e 脚本 | 
--expression=脚本 | 
添加脚本到将要执行的命令。 | 
-f 脚本文件 | 
--file=脚本文件 | 
添加脚本文件的内容到即将执行的命令。 | 
--follow-symlinks | 
处理已存在文件时跟随链接。 | |
-i[SUFFIX] | 
--in-place[=SUFFIX] | 
编辑已存在的文件(如果提供了SUFFIX作为后缀则做备份)。 | 
-l N | 
--line-length=N | 
指定 l 命令需要的自动换行长度。 | 
--posix | 
禁用所有GNU插件。 | |
-E -r | 
--regexp-extended | 
在脚本中使用扩展正则表达式(为了可移植性,请使用符合POSIX的-E)。 | 
-s | 
--separate | 
将多个文件分别看待,而非统一视作同个连续的流。 | 
--sandbox | 
在沙箱模式下操作。 | |
-u | 
--unbuffered | 
从输入文件中读取最少量的数据并更频繁地刷新输出缓冲区。 | 
-z | 
--null-data | 
用 NUL 字符分割行。 | 
--help | 
显示这个帮助并退出。 | |
--version | 
输出版本信息并退出。 | 
sed 命令提供的选项不多,核心在于脚本命令。sed 主要的脚本命令如下:
| 名称 | 说明 | 
|---|---|
: label | 
b 和 t 命令的标签。 | 
#comment | 
注释将会延长到下一个新行(或者一个 -e 脚本片段的结尾)。 | 
} | 
一个 { } 块的闭括号。 | 
= | 
答应当前行的行号。 | 
a \ text | 
追加 text, text 可以通过预先写入反斜杠来嵌入新行。 | 
i \ text | 
插入 text, text 可以通过预先写入反斜杠来嵌入新行。 | 
q [exit-code] | 
立即退出 sed 脚本而不处理其他输入,除非自动打印没有禁用使得当前模式空间将会被打印。[exit-code] 是 GNU 插件。 | 
Q [exit-code] | 
立即退出 sed 脚本而不处理其他输入。这是一个GNU插件。 | 
r 文件名 | 
从文件名读取内容并追加到最后。 | 
R 文件名 | 
从文件名读取一行并追加到最后。每次调用这个命令就从文件中读取一行。 | 
{ | 
开始一个命令块,以 } 符号结束。 | 
b label | 
程序跳转到 label 处;如果 label 被省略,跳转到脚本尾部。 | 
c \ text | 
用 text 代替选择的行, text 可以通过预先写入反斜杠来嵌入新行。 | 
d | 
删除模式空间。 | 
D | 
如果模式空间包含新行,在 d 命令发布之后开始一个新的普通循环。否则删除模式空间中的 text 直到新行,并且在不读入新行的情况下,用结果的模式空间开始一个循环。 | 
h H | 
复制 / 追加模式空间到保存空间。 | 
g G | 
复制 / 追加保存空间到模式空间。 | 
l | 
用直观明确的格式列出当前行。 | 
l width | 
用直观明确的格式列出当前行,在 width 字符处结束。这是一个 GNU 插件。 | 
n N | 
读取 / 追加下一行输入到模式空间。 | 
p | 
输出当前的模式空间。 | 
P | 
输出直到遇到当前模式空间的第一个嵌入的换行符。 | 
s/regexp/replacement/ | 
尝试与模式空间匹配 regexp,如果成功,用 replacement 代替匹配的部分 。replacement 可能包含特殊字符 & 来引用模式空间中匹配的部分,而特殊字符 \1 到 \9 则引用 regexp 中对应匹配的子表达式。 | 
t label | 
自上次输入行读取之后并且上次执行了 t 或者 T 命令之后,如果一个 s/// 被成功替换,那么跳转到 label 处;如果 label 被忽略,跳转到脚本结尾。 | 
T label | 
自上此输入行读取之后并借上次执行了 t 或者 T 命令之后,如果一个 s/// 被成功替换,那么跳转到 label 处;如果 label 被忽略,跳转到脚本结尾。这是一个 GNU 插件。 | 
w filename | 
将当前的模式空间写入到 filename 中。 | 
W filename | 
写入当前模式空间的第一行到 filename 中。这是一个 GNU 插件。 | 
x | 
交换模式空间和保存空间的内容。 | 
y/source/dest/ | 
将模式空间中显示为 source 的字符用 dest 字符来写出。 |