Sed基本入门[1] 基础知识
1、What's sed?
如果你是一个开发、系统管理员或者数据库管理员又或者是it管理员,或者只是一个经常在unix/linux环境下工作的人,你应该掌握sed和awk。
Sed→Stream Editor,它是一个非常强大的工具,可以用来操作、过滤和转换文本。Sed可以从文件中获取输入,也可以从管道中获取输入。
2、Basic Syntax
sed [options] {sed-commonds} {input-file}
sed一次从input-file中读取一行文本,然后在这一行文本上执行sed-commonds,接着读取下一行文本,再执行sed-commonds,重复执行这个过程,直到读取input-file的最后一行之后。
sed-commonds可以是一个命令也可以是一组命令。如果是一个命令,可以如以下的方式执行:
sed -n 'p' /etc/passwd
在上面的示例中,-n为选项 p为命令,/etc/passwd为输入文件。
如果需要执行的是一组命令,需要在每个命令前加上选项-e,表示是需要执行的命令,其基本语法为:
sed [options] -e {sed-command-1} -e {sed-command-2} {input-file}
示例:
$ sed -n -e '/^root/ p' -e '/^nobody/ p' /etc/passwd
如果通过几个-e参数执行多个命令,可以把他们通过反斜杠分成多行,例如:
$ sed -n \ -e '/^root/ p' \ -e '/^nobody/ p' \ /etc/passwd
你也可以把通过花括号把要执行的多个sed命令写到一组,其基本语法为:
sed [options] '{ sed-command-1 sed-command-2 }' input-file
示例:
$ sed -n '{ /^root/ p /^nobody/ p }' /etc/passwd
我们还可以把要执行的sed命令写到一个文件中,然后通过-f选项来使用该文件,其基本语法为:
sed [options] -f {sed-commands-in-a-file} {input-file}
示例:
$ vi test-script.sed /^root/ p /^nobody/ p $ sed -n -f test-script.sed /etc/passwd
3、Sed Scripting Flow
PEPR:
- Read:把一行文本读取到模式空间(Pattern Space,一个内部的临时buffer)。
- Execute:在模式空间内保存的文本上执行sed命令。如果有多个sed命令,则会依次执行。
- Print:打印输出模式空间中的文本,打印后,模式空间为空。
- Repeat:重复执行上述操作,直到文件的末尾。
具体流程可以参考下图:
4、p command and Address Range
在接下来的示例中,我们会多次以文本文件employee.txt作为sed操作的对象进行示范:
$ vi employee.txt 101,John Doe,CEO 102,Jason Smith,IT Manager 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer 105,Jane Miller,Sales Manager
使用p命令,可以打印当前模式空间中的内容。
为什么需要p命令?
在3 Sed Scripting Flow 中提到了Print,也就是说sed自动也会打印模式空间中的内容,那为什么还需要有一个专门的打印命令p呢?因为使用p命令,你可以更加详细的指定打印哪些内容或者说不打印哪些内容。通常情况下,使用p命令时,配合使用-n选项来抑制标准sed流程中的默认打印,否则文本可能会打印两行:
$ sed 'p' employee.txt 101,John Doe,CEO 101,John Doe,CEO 102,Jason Smith,IT Manager 102,Jason Smith,IT Manager 103,Raj Reddy,Sysadmin 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer 104,Anand Ram,Developer 105,Jane Miller,Sales Manager 105,Jane Miller,Sales Manager
使用-n选项后:
$ sed -n 'p' employee.txt 101,John Doe,CEO 102,Jason Smith,IT Manager 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer 105,Jane Miller,Sales Manager
Address Range:
通过在sed命令前指定地址范围,可以只在特定的行上执行sed命令,否则默认在所有的行上执行。例如以下代码片段只在第二行上执行打印命令:
$ sed -n '2 p' employee.txt 102,Jason Smith,IT Manager
而以下代码片段只在2到最后一行行上执行打印命令:
$ sed -n '2,$ p' employee.txt 102,Jason Smith,IT Manager 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer 105,Jane Miller,Sales Manager
常见的地址范围用法:
- n:匹配第n行
- n,m:匹配第n到m行
- n,+m:匹配从第n行及接下来的m行
- n~m:匹配从第n行开始的每m行记录,例如:1~2匹配1,3,5,7,...;2~2匹配2,4,6,8,...;2~3匹配2,5,8,....
模式匹配(Pattern Matching)
正如可以使用地址范围一样,也可以使用一个模式匹配,例如以下几个示例:
打印匹配模式"Jane"的行:
sed -n '/Jane/ p' employee.txt 105,Jane Miller,Sales Manager
打印从匹配模式"Raj"开始的行到匹配模式"Jane"的行:
$ sed -n '/Raj/,/Jane/ p' employee.txt 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer 105,Jane Miller,Sales Manager
甚至可以结合模式匹配和地址范围,例如打印从匹配模式"Jason"及后面的两行:
$ sed -n '/Jason/,+2 p' employee.txt 102,Jason Smith,IT Manager 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer
! 的用法:在地址范围或模式匹配后 加上 ! 可以表示原条件的相反条件,例如以下示例,如果没有加 ! 则表示打印1、3、5行,但是加上! 后,则表示打印其余的行
$ sed -n '1~2 ! p' employee.txt 102,Jason Smith,IT Manager 104,Anand Ram,Developer
5、Some Other Common commands
- d:Delete Lines
the lower case d command deletes the current pattern space, reads the next line from the input-file to the pattern space, aborts the rest of the sed commands and starts the loop again.
- w:Write Pattern Space to File
sed不会修改原文件的内容,只是修改模式空间中的内容
几个示例:
删除所有行:
sed 'd' employee.txt
删除第2行:
sed '2 d' employee.txt 101,John Doe,CEO 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer 105,Jane Miller,Sales Manager
删除1到4行:
$ sed '1,4 d' employee.txt 105,Jane Miller,Sales Manager
删除奇数行:
$ sed '1~2 d' employee.txt 102,Jason Smith,IT Manager 104,Anand Ram,Developer
删除第一次出现"Jason"的行到第4行:
$ sed '/Jason/,4 d' employee.txt 101,John Doe,CEO 105,Jane Miller,Sales Manager
删除空行:
sed '/^$/ d' employee.txt
删除注释行:
sed '/^#/ d' employee.txt
将employee.txt中的内容逐行写入文件output.txt中:
$ sed 'w output.txt' employee.txt 101,John Doe,CEO 102,Jason Smith,IT Manager 103,Raj Reddy,Sysadmin 104,Anand Ram,Developer 105,Jane Miller,Sales Manager
把第2行到最后一行的数据写入文件output.txt:
$ sed -n '2,$ w output.txt' employee.txt
6、直接修改原文件
我们已经知道了默认sed是不会修改原文件的,为了将修改后的文本写回原文件,可以有以下几种方法:
可以通过w命令将修改后的文本写入一个新文件,然后将新文件重命名为原文件的名字。(注意不能直接使用w命令将新内容写回原文件,否则原文件内容会被清空,达不到效果。)
sed -e '2d' -e 'w output.txt' employee.txt
mv output.txt employee.txt
还可以通过标准输出重定向写入一个新文件,然后将新文件重命名为原文件的名字。(注意重定向的文件不能是原文件,否则原文件内容会被清空,达不到效果。)
sed 's/John/Johnny/' employee.txt > new-employee.txt mv new-employee.txt employee.txt
以上两种方法都得通过一个中间的文件间接修改,其实可以通过一个选项 -i 来更直接的修改原文件。
$ sed -i 's/John/Johnny/' employee.txt
这样employee.txt的内容就直接被修改了,为了谨慎起见,我们可以通过以下方法在修改原文件前将原文件进行备份
sed -i.bak 's/John/Johnny/' employee.txt
这样就会首先将原文件备份为employee.txt.bak