但需注意,当没有下一行可供"n"读取时(例如文件的最后一行已经被读取过了),将输出模式空间内容后直接退出sed程序,使得"n"命令后的所有命令都不会执行,即使是那两个隐含动作。
相应的循环结构如下:
for ((line=1;line<=last_line_num;++line))
do
read $line to pattern_space;
while pattern_space is not null
do
execute cmd1 in SCRIPT;
execute cmd2 in SCRIPT;
ADDR1,ADDR2{ # "n" command
if [ "$line" -ne "$last_line_num" ];then
auto_print;
remove_pattern_space;
read next_line to pattern_space;
else
auto_print;
remove_pattern_space;
exit;
fi
};
……
auto_print;
remove_pattern_space;
done
done
注意,是先判断是否有下一行可读取,再输出和清空pattern space中的内容,所以then和else语句中都有这两个动作。 也许感觉上似乎更应该像下面这样的优化形式:
ADDR1,ADDR2{ # "n" command
auto_print;
remove_pattern_space;
[ "$line" -ne "$last_line_num" ] && read next_line to pattern_space || exit;
};
但事实证明并非如此,证明过程在本文结尾。此处暂不讨论这些复杂的东西,先看看"n"命令的示例。
例如,搜索a.txt中包含"redirect"字符串的行以及其下一行,并输出。
sed -n '/redirect/{p;n;p}' a.txt
再例如下面的命令。
echo -e "abc\ndef\nxyz" | sed '/abc/{n;=;p}'
abc
2
def
def
xyz
从结果中可以分析出,"n"读取下一行前输出了"abc",然后立即读入了下一行,所以输出的行号是2而不是1,因为这时候行号计数器已经读取了下一行,随后命令"p"输出了该模式空间的内容,输出后还有一次自动输出的隐含动作,所以"def"被输出了两次。
(7).替换命令"s"。
这是sed用的最多的命令。两个字就能概括其功能:替换。将匹配到的内容替换成指定的内容。
"s"命令的语法格式为:其中"/"可以替换成任意其他单个字符。
s/REGEXP/REPLACEMENT/FLAGS
它使用REGEXP去匹配行,将匹配到的那部分字符替换成REPLACEMENT。FLAGS是"s"命令的修饰符,常见的有"g"、"p"和"i"或"I"。
"g":表示替换行中所有能被REGEXP匹配的部分。不使用g时,默认只替换行中的第一个匹配内容。此外,"g"还可以替换成一个数值N,表示只替换行中第N个被匹配的内容。
"p":输出替换后模式空间中的内容。
"i"或"I":REGEXP匹配时不区分大小写。
REPLACEMENT中可以使用"\N"(N是从1到9的整数)进行后向引用,所代表的是REGEXP第N个括号(...)中匹配的内容。另外,REPLACEMENT中可以包含未转义的"&"符号,这表示引用pattern space中被匹配的整个内容。需要注意,"&"是引用pattern space中的所有匹配,不仅仅只是括号的分组匹配。
例如,删除a.sh中所有"#"开头(可以包括前导空白)的注释符号"#",但第一行"#!/bin/bash"不处理。
sed -i '2,$s/^[ \t]*#//' a.sh
为a.sh文件中的第5行到最后一行的行首加上注释符号"#"。
sed '5,$s/^/#/' a.sh
将a.sh中所有的"int"单词替换成"SIGINT"。
sed 's/\bint\b/SIGINT/g' a.sh
将a.sh中"cmd1 && cmd2 || cmd3"的cmd2和cmd3命令对调个位置。
sed 's%&&\(.*\) ||\(.*\)%\&\&\2 ||\1%' a.sh
这里使用了"%"代替"/",且在REPLACEMENT部分对"&"进行了转义,因为该符号在REPLACEMENT中时表示的是引用REGEXP所匹配的所有内容。
(8).追加、插入和修改命令"a"、"i"、"c"。
这3个命令的格式是"[a|i|c] TEXT",表示将TEXT内容队列化到内存中,当有输出流或者说有输出动作的时候,半路追上输出流,分别追加、插入和替换到该输出流然后输出。追加是指追加在输出流的尾部,插入是指插入在输出流的首部,替换是指将整个输出流替换掉。"c"命令和"a"、"i"命令有一丝不同,它替换结束后立即退出当前SCRIPT循环,并进入下一个sed循环,因此"c"命令后的命令都不会被执行。
例如:
echo -e "abc\ndef" | sed '/abc/a xyz'
abc
xyz
def