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

但需注意,当没有下一行可供"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

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

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