Linux sed 命令详解系列教程之入门篇(3)

'FIRST~STEP'
表示从第FIRST行开始,每隔STEP行就再取一次。也就是取行号满足FIRST+(N*STEP) (其中N>=0)的行。因此,要选择所有奇数行,使用"1~2";要从第2行开始每隔3行取一次,使用"2~3";要从第10行开始每隔5行取一次,使用"10~5";而"50~0"则表示只取第50行。

'$'
默认该符号匹配的是最后一个文件的最后一行,如果指定了"-i"或"-s",则匹配的是每个文件的最后一行。总之,"$"匹配的是每个输入流的最后一行。

需要注意的是,sed采用行号计数器来临时记录当前行的行号,因此sed在读取到最后一行前即使是倒数第二行的时候,完全不知道最后一行是第几行,所以代表最后一行的"$"无法进行任何数学运算,例如倒数第二行使用"$-1"表示是错误的。而且,"$"只是一个额外的标记符号,当sed读取到输入流的最后一行时,发现这就是最后一行,于是为此行打上"$"记号,并读取到模式空间中。

'/REGEXP/'
将选择能被正则表达式REGEXP匹配的所有行。如果REGEXP中自身包含了字符"/",则必须使用反斜线转义,即"\/"。

'/REGEXP/I'
和"/REGEXP/"是一样的,只不过匹配的时候不区分大小写。

'\%REGEXP%'
('%'可以使用其他任意单个字符替换。) 这和上一个定址表达式的作用是一样的,只不过是使用符号"%"替换了符号"/"。当REGEXP中包含"/"符号时,使用该定址表达式就无需对"/"使用反斜线"\"转义。但如果此时REGEXP中包含了"%"符号时,该符号需要使用"\"转义。
总之,定址表达式中使用的分隔符在REGEXP中出现时,都需要使用反斜线转义。

'ADDR1,+N'
匹配ADDR1和其后的N行。

'ADDR1,~N'
匹配ADDR1和其后的行直到出现N的倍数行。倍数可为随意整数倍,只要N的倍数是最接近且大于ADDR1的即可。 如ADDR1=1,N=3匹配1-3行,ADDR1=5,N=4匹配5-8行。而"1,+3"匹配的是第一行和其后的3行即1-4行。

另外,在定址表达式的后面加"!"符号表示反转匹配的含义。也就是说那些匹配的行将不被选择,而是不匹配的行被选择。

例如,以下几个定址的示例:

sed -n '3p' INPUTFILE
sed -n '3,5!p' INPUTFILE
sed -n '3,/^# .*/! p' INPUTFILE
sed -n '/abc/,/xyz/p' INPUTFILE
sed -n '!p' INPUTFILE  # 这个有悖常理,但确实是允许的

4.sed常用命令

sed命令很多,本文的只简单介绍几个最常见的。

(1).强制输出命令"p"。

该命令能强制输出当前模式空间的内容。即使使用了"-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{print};        # "p" command
        ……
        auto_print;
        remove_pattern_space;
    done
done

在sed处理的过程中,"p"和"auto_print"是两个输出动作,都是输出当前模式空间的内容,只不过auto_print是隐含动作。使用了"-n"选项,其所影响的动作仅是"auto_print",使其输出空内容。也因此,当没有使用"-n"选项时,模式空间的内容会被输出两次。

例如,仅输出标准输入的第2行内容。

[root@linuxidc ~]# echo -e 'abc\nxyz' | sed -n 2p
xyz

不加"-n"选项,在"p"输出之后,SCRIPT循环的结尾处还会被auto_print输出一次。

[root@linuxidc ~]# echo -e 'abc\nxyz' | sed 2p 
abc
xyz    # 这是p命令输出的结果
xyz    # 这是自动输出的结果

(2).删除命令"d"。

命令"d"用于删除整个模式空间中的内容,并立即退出当前SCRIPT循环,进入下一个sed循环,即读取下一行

循环大致格式如下:

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{delete;break};    # "d" command
        ……
        auto_print;
        remove_pattern_space;
    done
done

唯一需要注意的一点是立即退出当前SCRIPT循环,这意味着如果"d"命令后面还有其他的命令,则这些命令都不会执行。

例如:删除a.txt中的第5行,并保存到原文件中。

sed -i '5d' a.txt

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/12959.html