【shell】sed命令及常见用法

时间:2023-01-31 00:10:09

【背景】

sed全称为stream editor,是linux中很常见的一个文本处理命令。sed主要以行为单位处理文本,实现对输入数据进行增、删、替换等功能。该命令的执行流程是每次读入一行输入,处理数据并将结果打印到屏幕上,然后读入下一行数据并以此循环,输入文件的内容本身并无任何改变。若有需要也可以使用特定选项或者重定向来将结果保存到文件。


【命令格式】

sed命令根据实际的用途而在形式上会稍微有点差异,所以这里不给出统一的格式,而是在下面的实际例子中给出特定用途下的格式。


【常见用法】

1.替换特定字符串

命令形式:

sed 's/pattern/replace_str/[g]' filename
或者

cat filename | sed 's/pattern/replace_str/[g]'
因为sed命令也支持stdin作为输入。

或者

sed 'x[,y]c' filename
这里x,y代表行号,c表示替换命令。

例子:

(1)将输入的第一个me替换成ME:

echo mememe | sed 's/me/ME/'
输出为MEmeme。

(2)将输入的所有me替换成ME:

echo mememe | sed 's/me/ME/g'
输出为MEMEME,注意这里相比第一个例子新增了g,这代表sed会替换每一处匹配。

(3)将第1到2行数据替换为hahaha:

sed '1,2c hahaha' filename

2.删除特定行

命令形式:

sed 'x[,y]d' filename
这里x,y表示行号,d为删除命令

或者

sed '/pattern/d' filename
这里使用模式来匹配行,并将匹配成功的行删除掉
例子:

(1)删除文件test的第二行:

sed '2d' test
(2)删除文件test的第二到第三行:

sed '2,3d' test
另外,可以用$表示最后一行。

(3)删除空白行:

sed '/^$/d' filename


3.新增行

命令形式:

sed 'xa string'

x表示行号,a表示将string增加到x行的下一行

或者

sed 'xi string'
x表示行号,i表示将string增加到x行的上一行

例子:

(1)增加hello到第二行的下一行:

sed '2a hello' filename

4.打印特定行

命令形式:

sed -n 'x[,y]p' filename
x,y表示行号,p表示打印命令

或者

sed -n '/pattern/p' filename
这里使用模式匹配,能够和pattern匹配的行会被输出

注意需要使用-n选项(安静模式),否则特定/匹配成功的行会被打印两遍。


5.将输出保存到文件

sed的输出是打印到屏幕的,如果想输出到文件则需要额外操作。

(1)重定向:

sed 's/string/str/g' filename > newfile
确认newfile的内容无误后再替换掉filename即可。不过这样有点麻烦,还可以用下面的选项简化操作。

(2)使用-i选项

sed -i 's/string/str/g' filename
使用-i选项将结果保存到输入的文件中

(3)创建临时文件的方法

sed -i.tmp 's/string/str/g' filename
直接使用-i选项会覆盖输入文件,万一命令有误就会导致原有文件的内容被破坏,一个比较稳妥的办法是在-i选项后面增加文件后缀,这样会创建filename.tmp并将输出保存在该文件中,而原有文件不会被修改。


6.使用其他定界符

/字符是常见的sed定界符,但是也可以使用:、|作为定界符。

sed 's:string:str:' filename
sed 's|stirng|str|' filename


7.使用双引号

sed一般使用单引号,但是也可以使用双引号,此时会对变量进行求值。

text=hello
echo hello world | sed "s/$text/HELLO/"
输出为HELLO world


8.字符串匹配

&在sed中表示已经匹配的字符串,可用于一些特定场景。

例子:

(1)将输入的单词使用括号包围:

echo haha 1234 | sed 's/[a-zA-Z]\{1,\}/[&]/g'
该命令表示将单词周围加上方括号,其输出为[haha] 1234


9.子串匹配

如果想要表示匹配的其中一部分字符串,需要使用\x,x代表匹配的第x个字符串。

例子:

(1)交换输入的两个字符串:

echo hello world | sed 's/\([a-z]\{1,\}\) \([a-z]\{1,\}\)/\2 \1/'
输出就会从hello world变成world hello。这里每个需要匹配的模式都用()包括住了,然后用\2 \1表示输出第二个匹配的字符串 第一个匹配的字符串,即完成了交换。