这里不能使用重定向的方式保存,因为重定向是在sed命令执行前被shell执行的,所以会截断a.txt,使得sed读取的输入流为空,或者结果出乎意料之外。而"-i"选项则不会操作原文件,而是生成临时文件并在结束时重命名为原文件名。
删除a.sh中包含"#"开头的注释行,但第一行的#!/bin/bash不删除。
sed '/^#/{1!d}' a.sh
如果"d"后面还有命令,在删除模式空间后,这些命令不会执行,因为会理解退出当前SCRIPT循环。例如:
echo -e 'abc\nxyz' | sed '{/abc/d;=}'
2
xyz
其中"="这个命令用于输出行号,但是结果并没有输出被"abc"匹配的行的行号。
(3).退出sed程序命令"q"和"Q"。
使用"q"和"Q"命令的作用是立即退出当前sed程序,使其不再执行后面的命令,也不再读取后面的行。因此,在处理大文件或大量文件时,使用"q"或"Q"命令能提高很大效率。它们之间的不同之处在于"q"命令被执行后还会使用自动输出动作输出模式空间的内容,除非使用了"-n"选项。而"Q"命令则会立即退出,不会输出模式空间内容。另外,可以为它们指定退出状态码,例如"q 1"。
使用了"q"和"Q"的sed循环结构大致如下:
# "q"命令
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{auto_print;exit}; # "q" command
……
auto_print;
remove_pattern_space;
done
done
# "Q"命令
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{exit}; # "Q" command
……
auto_print;
remove_pattern_space;
done
done
例如,搜索脚本a.sh,当搜索到使用了"."或"source"命令加载环境配置脚本时就输出并立即退出。
sed -n -r '/^[ \t]*(\.|source) /{p;q}' a.sh
(4).输出行号命令"="。
"="命令用于输出最近被读取行的行号。在sed内部,使用行号计数器进行行号计数,每读取一行,行号计数器加1。计数器的值存储在内存中,在要求输出行号时,直接插入在输出流中的指定位置。由于值是存在于内存中,而非模式空间中,因此不受"-n"选项的影响。
这是一个依赖于输出流的命令,只要有输出动作就会追加在该输出流的尾部。
例如,搜索出httpd.conf中"DocumentRoot"开头的行的行号,允许有前导空白字符。
sed -n '/^[ \t]*DocumentRoot/{p;=}' httpd.conf
DocumentRoot "/var/www/html"
119
如果"="命令前没有"p"输出命令,且没有使用"-n"选项,则是输出在Document所在行的前一行,因为SCRIPT最后的自动输出动作也有输出流。
(5).字符一一对应替换命令"y"。
该命令和"tr"命令的映射功能一样,都是将字符进行一一替换。
例如,将a.txt中包含大写字母的YES、Yes等替换成小写的yes。
sed 'y/YES/yes/' a.txt
(6).手动读取下一行命令"n"。
在sed的循环过程中,每个sed循环的第一步都是读取输入流的下一行到模式空间中,这是我们无法控制的动作。但sed有读取下一行的命令"n"。
由于是读取下一行,所以它会触发自动输出的动作,于是就有了输出流。不仅如此,还应该记住的是:只要有读取下一行的行为,在其真正开始读取之前一定有隐式自动输出的行为。