1. 准备工作
准备备一个数据文件data.txt,内容如下:
101,Zhang san,Fu Jian
102,Li si,Shan Dong
103,Wang Wu,Bei Jing
104,Zhao Qian Sun,Zhe Jiang
105,Ge Lin,Shang Hai
每一行为一条数据,每条数据包含三个元素:ID,姓名和籍贯。
2. sed简介
Sed是 Stream Editor的缩写,即流编辑器的意思。它是一款非常出色的文本处理工具,可以操作、过滤转换文本。Sed的输入可以是文件,也可以是管道。刚接触sed时,常常感觉晦涩难懂,深入理解之后,又常惊叹于它的强大。本文介绍sed的基本语法。
3. sed命令语法
它的基本语法很简单:
sed [options] {sed-commands} {input-file}
sed每次读取{input-file}文件里的一行,并执行{sed-commands}命令,直到文件结束。同时,可以传递一些参数给sed命令,这就是 [options]里的内容。
你是不是已经跃跃欲试了呢?在你的终端上执行:
sed -n 'p' /etc/passwd
执行结果和cat没什么两样,没错,它只是把文件里的内容逐行打印而已。这里的 {sed-commands}只有一个'p'。你可以组合多条sed命令,并把它们写到一个文件里,然后用-f参数选项调用它:
sed [options] -f {sed-commands-in-a-file} {input-file}
写个简单的脚本test-script.sed,其内容如下:
/^root/ p
/^nobody/ p
然后执行命令:
sed -n -f test-script.sed /etc/passwd
结果有什么不同?这回只输出 /etc/passwd 里以root 和nobody 开头的行,不是吗?
如果只是执行简单的命令组合,再写个脚本也有点费事,想省事的话,那就直接用-e选项,直接把命令写上:
sed [options] -e {sed-command-1} -e {sed-command-2} {input-file}
sed -n -e '/^root/ p' -e '/^nobody/ p' /etc/passwd
如果命令组合比较长,可以用反斜杠换行:
sed -n \
-e '/^root/ p' \
-e '/^nobody/ p' \
/etc/passwd
如果需要执行一组命令,可以用花括号 { },其语法:
sed [options] '{
sed-command-1
sed-command-2
}' input-file
实例:
sed -n '{
/^root/ p
/^nobody/ p
}' /etc/passwd
注意:sed不会修改源文件,它只是把结果输入到stdout。如果你需要保存修改的内容,你需要把输出重定向到目标文件。
4. Sed 脚本流
sed脚本流程很简单,读取、执行、打印,然后重复。简单描述为REPR四个步骤,分别对应Read, Execute, Print,和 Repea。
• Read 读取一行内容,放入模式空间
• Execute 对模式空间执行sed 命令
• Print 输入模式空间的处理结果,输入后,模式空间被清空
• Repeat 逐行执行
5. 打印模式空间 (p 命令)
可以使用p命令打印当前模式空间里的内容。你可能有点疑惑,既然sed在执行完命令之后,缺省会输入处理后的结果,为什么还需要设置一个p命令?
因为,p命令允许你控制输出内容。通常,当使用p命令时,你需要一个-n参数,否则,你会发现每一行都被打印了两次:
sed 'p' data.txt
sed -n 'p' data.txt
- 限定处理范围
如果你没有在sed命令之前限定处理范围,那么它缺省会处理输入文件里的所有行。如果你只需要处理其中的某一行,怎么办?下面示例只处理第二行:
sed -n '2 p' data.txt
处理前三行:
sed -n '1,3 p' data.txt
从第二行开始到输入结束:
sed -n '2,$ p' data.txt
- 控制修改范围
你可以通过逗号、加号和波浪号来控制修改范围。在前面的示例中,我们已经用到了逗号来限定范围,它的语义很明确:n,m表示从n到m。
可以用加号(+)结合逗号,来限定一系列行,而不必使用绝对的行号,比如说:n,+m表示从第n行开始的m行内。
还可以用波浪号 (~)来限定范围。它的含义是跳过。比如说:n~m表示从第n行开始处理,然后每隔m行处理一次。具体实例:
• 1~2 处理1,3,5,7, 等等
• 2~2 处理2,4,6,8, 等等
• 1~3 处理1,4,7,10, 等等
• 2~3 处理2,5,8,11, 等等
只打印奇数行:
sed -n '1~2 p' data.txt
- 模式匹配
除了指定行号之外,你还可以指定匹配模式,比如说,找出福建人:
sed -n '/Fu Jian/ p' data.txt
找出第一次出现“Fu Jian”之后,到第四行的内容:
sed -n '/Fu Jian/,4 p' data.txt
通过两个模式限定起始范围:
sed -n '/Fu Jian/,/Shan Dong/ p' data.txt
6. 删除行(d命令)
可以用d命令删除当前行。请注意,删除仅作用于输出流,并不是删除源文件里的内容。sed的删除命令和打印命令一样,不会影响源文件。
删除所有内容:
sed 'd' data.txt
删除第2行:
sed '2 d' data.txt
删除前四行
sed '1,4 d' data.txt
删除所有空行:
sed '/^$/ d' data.txt
删除注释行
sed '/^#/ d' data.txt
注意,如果多条sed命令组合,如果碰到删除命令d,整个匹配的模式都会被删除,后续的命令也就不会执行了。
7. 把模式空间的内容写入文件(w命令)
通过w命令,可以把当前模式空间里的内容写入文件。缺省情况下,当前内容会被输出到stdout,如果你希望输出到文件而不是屏幕上,那么需要使用sed参数选项-n。
sed 'w output.txt' data.txt
sed -n 'w output.txt' data.txt
满园限定和之前所述相似。但是,你可能不常用w命令。而是用重定向'>'。比如说
sed 'p' data.txt > output.txt