sed 函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fhc2007@fhc2007-desktop:~$ sed --help
用法: sed [选项]... {脚本(如果没有其他脚本)} [输入文件]...
-n, --quiet, --silent
取消自动打印模式空间
-e 脚本, --expression=脚本
添加“脚本”到程序的运行列表
-f 脚本文件, --file=脚本文件
添加“脚本文件”到程序的运行列表
-i[扩展名], --in-place[=扩展名]
直接修改文件(如果指定扩展名就备份文件)
-l N, --line-length=N
指定“l”命令的换行期望长度
--posix
关闭所有 GNU 扩展
-r, --regexp-extended
在脚本中使用扩展正则表达式
-s, --separate
将输入文件视为各个独立的文件而不是一个长的连续输入
-u, --unbuffered
从输入文件读取最少的数据,更频繁的刷新输出
--help 打印帮助并退出
--version 输出版本信息并退出

如果没有 -e, –expression, -f 或 –file 选项,那么第一个非选项参数被视为sed脚本。其他非选项参数被视为输入文件,如果没有输入文件,那么程序将从标准输入读取数据。

注:-n 参数和 -i 参数不要一起使用。

本章将以一节一个函数参数的方式 ,介绍所有 sed 提供的函数参数 , 其中有

|s|d|a|i|c|p|l|r|w|y|!|n|q|=|#|N|D|P|h|H|g|G|x|b|t|

另外 , 在各节中 , 首先简单介绍函数参数功能 , 接着说明函数参数与位址参数配合的格式 ,而其中也一并描述 sed 执行此函数参数的工作情形。

s

函数参数 s 表示替换(substitute)文件内字串。其指令格式如下 :

1
[address1[, address2]]s/pattern/replacemen/[flag]

对上述格式有下面几点说明 :

  1. 函数参数 s 最多与两个位址参数配合。
  2. 关於 “s/pattern/replacement/[flag]“ 有下面几点说明:
  • pattern : 它为 reguler expression 字串。它表示文件中要被替换的字串。
  • replacement : 它为一般字串。但其内出现下列元字符有特别意义 :

    • & : 代表其前 pattern 字串。例如

      1
      sed -e 's/test/& my car/' 资料档名

      指令中 , & 代表 pattern 字串 “test“。故执行後 , 资料档的 “test“ 被替换成 “test my car“。

    • n : 代表 pattern 中被第 n (n 是从 1 到 9 的数字)个 () 所括起来的字串。例如

      1
      sed -e 's/(test) (my) (car)/[2 3 1]/' 资料档名

      指令中 , 1 表示 “test“、2 表示 “my“、3 表示 “car“ 字串。故执行後 , 资料档的 “test my car“被替换成 “[my car test]“。(注解:()1 ... 9 合用)

    • \ : 可用它来还原一些特殊符号(如上述的 & 和 \ )本身字面上的意义(转义) , 或用它来代表换行
  • flag : 主要用它来控制一些替换情况 :

    • 当 flag 为 g 时 , 代表替换所有符合(match)的字串 。
    • 当 flag 为十进位数字 m 时 , 代表替换行内第 m 个符合的字串。
    • 当 flag 为 p 时 , 代表替换第一个符合 pattern 的字串後 , 将资料输出标准输出档。
    • 当 flag 为 w wfile 时 , 代表替换第一个符合 pattern 的字串後 , 输出到 wfile 档内(如果 wfile 不存在 , 则会重新开启名为 wfile 的档案)。
    • 当没有 flag 时 , 则将资料行内第一个符合 pattern 的字串以 replacement 字串来替换 。
  • delimiter : 在 “/pattern/replace/[flag]“ 中 “/“ 被当成 delimiter。除了空白(blank)、换行(newline) 之外 ,使用者可用任何字元作为 delimiter。例如下述编辑指令

    1
    s#/usr#/usr1#g

    上述命令中”#“为 delimiter。如果用 “/“ 做 delimiter , 则 sed 会将 pattern 与 replacement中的 “/“ 当成 delimiter 而发生错误。

范例

题目: 替换 input.dat 档(後面如果没有特别指定 , 均假设文件档名为 input.dat)内 “1996“ 字串成 “1997“ , 同时将这些资料行存入 year97.dat 档内。

说明: 用函数参数 s 指示 sed 将 “1996“ 字串替换成 “1997“ , 另外用 s argument 中的 flag w 指示 sed 将替换过的资料行存入 year97.dat 档内。

sed 命令列:

1
sed -e 's/1996/1997/w year97.dat' input.dat

数字标志很少使用,在这种情况下,正则表达式在一行上重复匹配,而只需对其中某个位置的匹配进行替换。例如,某输入行也许包含 [tab](制表符)输入,也许包含多个制表位。假设每行有3个制表符,并且要用“>”替换第二个制表位,则可以使用下面的替换命令来完成该功能:

1
s/[tab]/>/2

[tab]“表示一个真正的制表符,而制表符在屏幕上是不可见的。如果输入是一行的文件,如下所示:

1
Column1[tab]column2[tab]Column3[tab]Column4

对这个文件运行以上脚本产生的输出如下:

1
Column1[tab]column2>Column3[tab]Column4

注意,如果没有数字标志,则替换命令只替换第一个制表符(因此“1”可以被看作是默认的数字标志)。
我们可以对前面的示例做一些改动,用换行符取代每行上的第二个制表符。

1
2
s/[tab]/
/2

注意,在反斜杠后面不允许有空格。这个脚本产生下面的结果:

1
2
Column1[tab]column2
Column3[tab]Column4

d

函数参数 d 表示删除资料行 , 其指令格式如下:

1
[address1[, address2]]d

对上述格式有下面几点说明:

  1. 函数参数 d 最多与两个位址参数配合。
  2. sed 执行删除动作情况如下 :

    1. 将 pattern space 内符合位址参数的资料删除。
    2. 将下一笔资料读进 pattern space 。
    3. 重新执行 sed script。

补遗:删除命令是一个可以改变脚本中的控制流的命令。这是因为一旦执行这个命令,那么在“空的”模式空间(注:不允许在被删除的行上进行进一步操作)中就不会再有命令执行。所以,删除命令会导致读取新的输入行,而编辑脚本则从头开始新的一轮。重要的是:如果某行匹配了模式中地址(地址参数),那么就删除整个行,而不只是删除行中匹配的部分(要删除行的一部分,可以使用替换命令并指定一个空的替换)。

a

函数参数 a 表示将资料添加到文件中。其指令格式如下:

1
[address1]a 使用者所输入的资料

对上述格式有下面几点说明:

  1. 函数参数 a 最多与一个位址参数配合。
  2. 函数参数 a 紧接着 “\“ 字元用来表示此行结束 , 使用者所输入的资料必须从下一行输入。如果资料超过一行 , 则须在每行的结尾加入”\n“。
  3. sed 执行添加动作情况如下: 当 pattern space 内资料输出後 , sed 跟着输出使用者所输入的资料。

范例

题目: 添加 “多工作业系统“ 在含 “UNIX“ 字串的资料行後。假设 input.dat 档的内容如下:

1
UNIX

说明: 用函数参数 a 将所输入的资料添加在含 “UNIX” 字串的资料行後。

sed 命令列如下:

1
2
3
sed -e '/UNIX/a\
多工作业系统
' input.dat

执行上述命令後, 其输出结果如下:

1
2
UNIX
多工作业系统

多行资料输入

1
2
3
sed -e '/UNIX/a\
多工\n作业系统
' input.dat

执行上述命令后,其输出结果如下:

1
2
3
UNIX
多工
作业系统

当然,上述命令也可以在一行中输入:

1
sed -e '/UNIX/a 多工\n作业系统' input.dat

命令结果同上。

i

函数参数 i 表示将资料插入文件中。其指令格式如下:

1
[address1]i 使用者所输入的资料

对上述格式有下面几点说明:

  1. 函数参数 i 最多与一个位址参数配合。
  2. 函数参数 i 紧接着 “\“ 字元用来表示此行结束, 使用者所输入的资料必须从下一行输入。如果资料超过一行 , 则须在每行的结尾加入”\n“。
  3. sed 执行插入动作的情况如下: 在 pattern space 内资料输出前 , sed 先输出使用者所输入的资料。

范例

题目: 将 “文章版权属於中央研究院“ 插在 input.dat 档中含 “院长: 李远哲“ 的资料行之前。假设 input.dat 档内容如下 :

1
院长: 李远哲

说明: 用函数参数 i 将资料行 “文章版权属於中央研究院“ 插在含 “院长: 李远哲“ 的资料行之前。

sed 命令列如下:

1
2
3
sed -e '/院长:李远哲/i\
文章版权属於中央研究院
' input.dat

执行上述命令後的输出如下:

1
2
文章版权属於中央研究院
院长: 李远哲

c

函数参数 c 表示改变文件中的资料。其格式如下:

1
[address1[, address2]]c 使用者所输入的资料

对上述格式有下面几点说明:

  1. 函数参数 c 最多与两个位址参数配合。
  2. 函数参数 c 紧接着 “\“ 字元用来表示此行结束, 使用者所输入的资料必须从下一行输入。如果资料超过一行 , 则须在每行的结尾加入”\n”。
  3. sed 执行改变动作的情况: 在 pattern space 内资料输出时, sed 改变它成为使用者所输入的资料。

补遗:更改命令清除模式空间,它在空间模式中与删除命令有同样的效果。脚本中在更改命令之后的其他命令没有被提供。
插入命令和追加命令不影响模式空间的内容。提供的文本将不匹配脚本中后续命令中的任何地址,那些命令也不影响该文本。不管什么更改改变了模式空间,所提供的文本仍然会正确输出。当默认的输出受到抑制时也是这样——所提供的文本将被输出,即时模式空间不是那样的。而且,所提供的文本不影响 sed 的内部行计数器。

p

函数参数 p 表示印出模式空间中的资料。其指令格式如下 :

1
[address1[, address2]]p

对於上述格式有下面几点说明 :

  1. 函数参数 p 最多与两个位址参数配合。
  2. sed 执行印出动作的情况如下: sed 拷备一份 pattern space 内容至标准输出档。

除非抑制(-n)默认的输出,否则打印命令将输出行的重复复制。当抑制默认的输出或者当通过程序的流程控制来避免到达脚本的底部时,可能会使用它。

l

函数参数 l , 除可将模式空间资料中的 nonprinting character(非打印字符) 显示为两个数字的ASCII 代码(GNU sed 显示某些字符,例如,回车符,使用的是 ANSI C 转义序列,而不是八进制。)外 , 其於均与函数参数 p 相同。例如 , 将下面 input.dat 档中的 ^[ 以 ASCII 码印出

1
The Great ^[ is a movie starring Steve McQueen.

(在 vi 中的插入模式下通过键入 CTRL-V(大小写无关),然后按下 ESC 键,产生字符 ^[ ,类似的,按下回车键可产生字符 ^M,按下 CTRL-A(大小写无关),产生字符 ^A,其余类推。)

执行命令

1
sed -e 'l' input.dat

後, 则输出结果如下:

1
2
The Great 33 is a movie starring Steve McQueen.
The Great is a movie starring Steve McQueen.

上述第二行资料为 sed 的自动输出。

(在 sed 中不能用 ASCII 值匹配字符(也不能匹配八进制数值),所以,使用 sed 替换(或删除)文档中的非打印字符,得用 vi 来编辑 sed 的编辑命令脚本,使用命令脚本来执行 sed 而无法在命令行上输入 sed 的命令参数。)

r

函数参数 r 表示读入文件的内容到模式空间。其指令格式如下 :

1
[address1]r file

对於上述格式有下面几点说明:

  1. 函数参数 r 最多与一个位址参数配合。
  2. 在指令中, 函数参数 r 与文件名称间, 必须有一空格(空格后到换行符前的每个字符都被当做文件名,因此,前导的和嵌入的空格也是文件名的一部分)。
  3. sed 执行读入动作的情况如下: 在 pattern space 内资料输出後, sed 读入由 file 指定的文件的内容跟着输出。当 file 不存在时, sed 照样执行其它指令而不会有任何错误讯息产生。

w

函数参数 w 表示将模式空间的内容写入文件。其指令格式如下 :

1
[address1[, address2]]w file

对於上述格式有下面几点说明 :

  1. 函数参数 w 最多与两个位址参数配合。
  2. 在指令中, 函数参数 w 与文件名称间 , 必须有一空格(空格后到换行符前的每个字符都被当做文件名,因此,前导的和嵌入的空格也是文件名的一部分)。
  3. sed 执行写出动作的情况如 : 将 pattern space 内资料写入文件 file。资料写入时 , 会取代(overwrite)原来文件内的资料(如果一个脚本中有多个指令写到同一个文件中,那么每个写命令都将内容追加到这个文件中)。另外, 当文件不存在时, sed 会重新产生(creat)它。

y

函数参数 y 表示转换资料中的字元。其指令格式如下 :

1
[address1[, address2]]y /xyz.../abc.../

对於上述格式有下面几点说明 :

  1. 函数参数最多配合两个位址参数。
  2. 指令中, /abc.../xyz.../(x、y、z、a、b、c 代表某些字元) 为 y 的 argument 。其中 abc...xyz... 的字元个数必须相同。
  3. sed 执行转换时, 将 pattern space 内资料内的 a 字元转换成 x 字元 、b 字元转换成 y 字元 、c 字元转换成 z 字元 …。

范例

题目:input.dat 档中的小写字母改成大写。假设 input.dat 档的内容如下 :

1
2
3
Sodd's Second Law:
Sooner or later, the worst possible set of
circumstances is bound to occur.

说明: 利用函数参数 y 指示 sed 做字母大小的转换。

sed 命令列如下:

1
2
3
sed -e '
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
' input.dat

执行上述命令输出结果如下 :

1
2
3
SODD'S SECOND LAW:
SOONER OR LATER, THE WORST POSSIBLE SET OF
CIRCUMSTANCES IS BOUND TO OCCUR.

!

函数参数 ! 表示不执行函数参数。当有如下指令时 ,

1
[address1[, address2]]! 函数参数

表示, 对符合位址参数之资料不执行函数参数。例如删除 , 除了含有 “regular” 字串的资料行外,所有资料行, 则执行 ! 后的删除命令

1
sed -e '/regular/!d' input.dat

n

函数参数 n 表示读入下一行资料。其指令格式如下:

1
[address1[, address2]]n

对上述格式有下面几点说明 :

  1. 函数参数 n 最多配合两个位址参数。
  2. sed 执行读入下一行动作的情况如下 :

    1. 输出在 pattern space 的资料(默认输出)。
    2. 将下一笔资料读到 pattern space。
    3. 执行下一个编辑指令(不用返回到脚本的顶端)。

补遗:next 命令改变了正常的流控制(正常情况下,直到到达脚本的底部才会输出模式空间的内容,总是在读入新行之后从脚本的顶端开始)。实际上,next 命令导致输入的下一行取代模式空间中的当前行。脚本中的后续命令应用于替换后的行,而不是当前行。如果没有抑制默认输出,那么在替换发生之前会打印当前行。在较长的脚本中,必须记住出现在 next 命令之前的命令不会应用于新的输入行,而出现在其后面的命令不应用于旧的输入行

范例

题目: 输出 input.dat 档内偶数行资料。假设 input.dat 档内容如下:

1
2
3
4
The
UNIX
Operation
System

说明: 在命令列上

  • 以选项 -n , 将资料输出的控制权转给指令。
  • 利用函数参数 n 将下一行资料(偶数行)取代 pattern space 内的资料行(奇数行)。
  • 利用函数参数 p 将 pattern space 内的资料(偶数行)输出。
    最後 , 整个输出只有原先档内的偶数行资料。

sed 命令列如下:

1
sed -n -e 'n' -e 'p' input.dat

执行上述命令後, 输出的结果如下:

1
2
UNIX
System

q

函数参数 q 表示跳离 sed 。其指令格式如下:

1
[address1]q

对上述格式有下面几点说明 :

  1. 函数参数 q 最多配合一个位址参数。
  2. sed 执行跳离动作时 , 它停止读取新的输入行(并停止将它们发送到输出)。

(退出命令 q 只适用于单行的地址。一旦找到和 address 匹配的行,那么脚本就结束。注:需要小心的是,在将编辑操作写回到原始文件的任何程序中不要使用 q 命令。在执行 q 命令之后,就不会再产生输出。在想要编辑文件的一部分并保留剩余部分不改变的情况下,不要使用 q 命令。这种情况下使用 q 时初学者常犯的非常危险的错误。)

示例,下面一行命令使用退出命令从文件中打印前100行:

1
2
$ sed '100q' test
...

它打印每一行,直到它到达行100并且退出。在这点上,这个命令的功能与 UNIX 的 head 命令类似。
quit 的另一个可能的用法是从文件中提取了想要的内容后退出脚本。

范例

题目: 对文件档执行 script_file 内的编辑指令 , 除非遇到 “Linux“ 字串。

说明: 无论 script_file 内是何种指令 , 使用者只要在命令列上用指令/Linux/q , 函数参数 q 会强迫 sed 遇到 “Linux“ 时做跳离动作。

sed 命令列如下:

1
sed -e '/Linux/q' -f script_file input.dat

=

函数参数 = 表示印出资料的行号。其指令格式如下:

1
[address1[, address2]]=

对上述格式有下面几点说明 :

  1. 函数参数 = 最多配合两个位址参数。
  2. 执行时, 行号将在资料输出前先输出。

范例:

题目: 印出 input.dat 档内资料行数。假设 input.dat 的内容如下 :

1
2
The UNIX
Operating System

说明: 用函数参数 = 来印出资料的行数。

sed 命令列如下:

1
sed -e '=' input.dat

执行上述命令後 , 输出的结果如下 :

1
2
3
4
1
The UNIX
2
Operating System

#

在 script file 内 , 函数参数 # 後的文字为注解。当注解文字超过多行时 , 其行间须以 “\n” 换行字元相隔。在 sed 的System V版本中,注释只允许出现在第一行。而 GNU sed 则可以在脚本的任何地方放置注释,甚至是跟在命令行的后面。注释行的第一个字符必须是“#”号。如果跟在#后面的下一个字符是n,那么脚本不会自动产生输出。这和指定命令行选项 -n 是等价的。跟在 n 后面的其余内容被看做是注释。在POSIX标准中,采用这种方式的 #n 必须是文件的前两个字符

到此为止,前面介绍的命令(函数参数)可归类为基本的 sed 命令,下面将要介绍的这些命令可归类为 sed 的高级命令。sed 的高级命令可分成3个组:

  1. 处理多行模式空间(NDP)。
  2. 采用保持空间来保存模式空间的内容并使它可用于后续的命令(HhGgx)。
  3. 编写使用分支和条件指令的脚本来更改控制流(:bt)。

多行模式空间

在前面的正则表达式讨论中,我们强调模式匹配是面向行的。像 grep 这样的程序尝试在单个输入行上匹配一个模式。这就使它很难匹配一个在一行的结尾处开始,并在下一行的开始处结束的短语。其他一些模式只有当在多行上匹配才有意义。
sed 能查看模式空间的多个行。这就允许匹配模式扩展到多行上。下面我们将要介绍创建多行模式空间并处理它的内容的命令。这里的 3 个多行命令(NDP)对应于前面介绍的小写字母的基本命令(ndp)。

N

函数参数 N 表示添加下一笔资料在 pattern space 内。其指令格式如下:

1
[address1[, address2]]N

对上述格式有下面几点说明 :

  1. 函数参数 N 最多配合两个位址参数。
  2. sed 执行时, 将下一行资料读入并添加在 pattern space 内, 资料行间以换行字元(embedded newline character)分隔。此外 , 在替换时 , 换行字元可用转义序列 \n 来匹配。

在多行模式空间中,元字符“^”匹配模式空间中的第一个字符,而不匹配换行符后面的字符。同样,“$”只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符。在执行 Next 命令之后,控制将被传递给脚本中的后续命令(同 next )。Next 命令与 next 命令不同,next 输出模式空间的内容,然后读取新的输入行。next 命令不创建多行模式空间。

范例

题目: 将下述两行资料合。假设 input.dat 的内容如下 :

1
2
The UNIX
Operating System

说明: 先利用函数参数 N 将两行资料置於 pattern space 内 , 在利用函数参数 s/\n/ / 将两行资料间的分隔符 \n 以空白替代 , 如此两行资料变成一行输出。

sed 命令列如下:

1
sed -e 'N' -e 's/\n/ /' input.dat

执行上述命令後 , 其输出的结果如下:

1
The UNIX Operating System

D

函数参数 D 表示删除 pattern space 内的第一行资料(删除模式空间中直到第一个嵌入的换行符的这部分内容)。其指令格式如下:

1
[address1[, address2]]D

对上述格式有下面几点说明 :

  1. 函数参数 D 最多配合两个位址参数。
  2. 函数参数 Dd 的比较如下 :
  • 当 pattern space 内只有一资料行时 , Dd 作用相同。
  • 当 pattern space 内有多行资料行时

    • D 表示只删除 pattern space 内第一行资料 ; d 则全删除。
    • D 表示执行删除后 , pattern space 内不添加下一笔资料 , 而将剩下的资料重新执行 sed script (返回到脚本的顶端,将这些指令应用于模式空间剩余的内容); d 则读入下一行后重新执行 sed script(返回到脚本的顶端)。

P

函数参数 P 表示印出 pattern space 内的第一行资料(输出多行模式空间的第一部分,直到第一个嵌入的换行符为止)。其指令格式如下:

1
[address1[, address2]]P

对上述格式有下面几点说明 :

  1. 函数参数 P 最多配合两个位址参数。
  2. Pp , 除了面对的 pattern space 内的资料行数不同外 , 其它均相同。

在执行完脚本的最后一个命令之后,模式空间的内容自动输出(-n 选项或 #n 抑制这个默认的动作)。因此当默认的输出被抑制或者脚本中的控制流更改,以至不能达到脚本的底部时,需要使用打印命令(Pp)。Print 命令经常出现在 Next 命令之后和 Delete 命令之前。这 3 个命令能建立一个输入/输出循环,用来维护两行的模式空间,但是一次只输出一行。这个循环的目的是只输出模式空间的第一行,然后返回到脚本的顶端将所有的命令应用于模式空间的第二行。没有这个循环,当执行脚本中的最后一个命令时,模式空间中的这两行都被输出。

范例

题目: 输出 input.dat 档内奇数行资料。假设 input.dat 档内容如下:

1
2
3
The
UNIX
System

说明: 在命令列上

  • 以选项 -n, 将资料输出的控制权转给指令。
  • 利用函数参数 N 将偶数行添加至 pattern space 内奇数行後。
  • 利用函数参数 P 将 pattern space 内的第一行(奇数行)输出。

在奇数行输出後 , pattern space 内剩下的资料行(偶数行)则被放弃输出。最後 , 整个输出只有原先的奇数行资料。

sed 命令列:

1
sed -n -e 'N' -e 'P' input.dat

执行上述命令後, 输出的结果如下:

1
2
The
System

模式空间与保持空间

模式空间的内容可以复制到保持空间,而且保持空间的内容也可以复制到模式空间。有一组命令用于在保持空间和模式空间之间移动数据。保持空间用于临时存储。单独的命令不能寻址保持空间或者更改它的内容。

保持空间最常见的用途是,当改变模式空间中的原始内容时,用于保留当前输入行的副本。影响模式空间的命令有:

命令 缩写 功能
Hold h 或 H 将模式空间的内容复制或追加到保持空间
Get g 或 G 将保持空间的内容复制或追加到模式空间
Exchang x 交换模式空间和保持空间的内容

hold(hH)命令将数据移至保持空间,而 get(gG)命令将保持空间的数据移回到模式空间。同一命令的小写字母和大写字母之间的差别是,小写字母命令改写目的缓存区的内容,而大写字母命令追加缓存区的现有内容。

hold(小写)命令用模式空间的内容取代保持空间的内容。get(小写)命令用保持空间的内容取代模式空间的内容。
Hold(大写)命令在保持空间的内容之后放置一个换行符,且后面跟随模式空间的内容(即使保持空间是空的,换行符也被追加到保持空间)。Get(大写)命令在模式空间的内容之后放置一个换行符,且后面跟随保持空间的内容。

交换命令交换两个缓存区的内容。对两个缓存区没有副作用。

h

函数参数 h 表示暂存 pattern space 的资料至 hold space。其指令格式如下:

1
[address1[, address2]]h

对上述格式有下面几点说明 :

  1. 函数参数 h 最多配合两个位址参数。
  2. sed 执行暂存动作时 , 会盖掉(overwrite) hold space 内原来的资料。
  3. 当 sed 全部执行结束时 , hold space 内资料会自动清除。

H

函数参数 Hh 唯一差别是 , sed 执行 h 时 , 资料盖掉(overwrite) hold space 内原来的资料 ,而 H , 资料则是 “添加(append)” 在 hold space 原来资料後。

g

函数参数 g 表示与函数参数 h 相反的动作 , 它表示将 hold space 内资料放回 pattern space内。其指令格式如下 :

1
[address1[, address2]]g

函数参数 g 最多配合两个位址参数。
sed 执行放回动作时 , 资料盖掉(overwrite) pattern space 内原来的资料。

G

函数参数 Gg 唯一差别是 , sed 执行 g 时 , 资料盖掉(overwrite) pattern space 内原来的资料 , 而 G , 资料则是 “添加(append)” 在 pattern space 原来资料後。

x

函数参数 x 表示交换 hold space 与 pattern space 内的资料。其指令格式如下 :

1
[address1[, address2]]x

函数参数 x 大部份与其它处理 hold space 的函数参数一起配合。例如 , 将 input.dat 档内第 1 行资料取代第 3 行资料。此时 , 用函数参数 hx 来配合。其中 , 以函数参数 h 将第 1 资料存入 hold space ;当第 3 行资料出现在pattern space , 以函数参数 x 交换 hold space 与 pattern space 的内容。如此 , 第 3 行资料就被第 1 资料替代。其命令列如下:

1
sed -e '1h' -e '3x' input.dat

高级流程控制指令

分支(b)和测试(t)命令将脚本中的控制转移到包含特殊标签的行。如果没有指定标签,则将控制转移到脚本的结尾处。分支命令用于无条件转移,测试命令用于有条件转移,它们只有当替换命令改变当前行时才会执行。
标签是任意不多于7个字符的序列(GNU sed 允许标签为任意长度)。标签本身占据一行并以冒号开始:

1
:mylabel

在冒号和标签之间不允许有空格。行结尾处的空格将被认为是标签的一部分。当在分支命令或测试命令中指定标签时,在命令和标签之间允许有空格:

1
b mylabel

注意,不要在标签后面插入空格。

b :label

函数参数 : 与函数参数 b 可在 sed script 内建立类似 BASIC 语言中 GOTO 指令的功能。其中 , 函数参数 : 建立标记;函数参数 b 将下一个执行的指令 branch 到标记处执行。函数参数 :b , 在 script file 内配合的情况如下

1
2
3
4
5
6
7
8
9
10
.
.
.
编辑指令m1
:记号
编辑指令m2
.
.
.
[address1[, address2]]b [记号]

其中, 当 sed 执行至指令[address1[, address2]]b [记号]时 , 如 pattern space 内的资料符合位址参数 , 则 sed 将下一个执行的位置 branch 至由 :记号设定的标记处 , 也就是再由 “编辑指令 m2“ … 执行。另外 , 如果指令中函数参数 b 後没有记号 , 则 sed 将下一个执行的指令 branch 到 script file 的最後 , 利用此可使 sed script 内有类似 C 语言中的 case statement 结构。

范例

题目:input.dat 档内资料行的开头字母重覆印 40 次。假设 input.dat 档的内容如下 :

1
2
3
A
B
C

说明: 用指令 b p1:p1 构成执行增加字母的回圈(loop) , 同时在字母出现 40 个时 , 也用指令 b 来跳出圈。下面就以档内第一行资料 “A“ 为例 , 描述它如何连续多添加 39 个 “A“ 在同一行:

  • 用指令 s/A/AA/ 将 “A“ 替换成 “AA“。
  • 用指令 b p1:p1 构成回圈(loop) , 它目的使上述动作被反覆的执行。每执行一次圈 , 则资料行上的 “A“ 就多出一个。例如 , 第一次圈资料行变成 “AA“ , 第二次圈资料行变成 “AAA“ …。
  • 用指令 [ABC]\{40\}/b (注解:\{重复次数\}\{下限,上限\})来作为停止回圈的条件。当资料行有连续 40 个 A 出现时 , 函数参数 b 将执行的指令跳到最後 , 停止对此行的编辑。

同样, 对其它资料行也如同上述的方式执行。

sed 命令列如下:

1
2
3
4
5
6
7
8
sed -e '{
:p1
/A/s/A/AA/
/B/s/B/BB/
/C/s/C/CC/
/[ABC]\{40\}/b
b p1
}' input.dat

命令结果输出:

1
2
3
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

t

基本上, 函数参数 t 与 函数参数 b 的功能类似 , 除了在执行 t 的 branch 前 , 会先去测试其前的替换指令有没有执行替换成功外。在 script file 内的情况如下:

1
2
3
4
5
6
7
8
9
10
11
12
.
.
.
编辑指令m1
:记号
编辑指令m2
.
.
.
s/.../.../
[address1[, address2]]t [记号]
编辑指令m3

其中 , 与函数参数 b 不同处在於, 执行函数参数 t branch 时, 会先检查其前一个替换指令成功与否。如成功, 则执行 branch; 不成功, 则不 branch, 而继续执行下一个编辑指令, 例如上面的编辑指令m3

范例

题目:input.dat 档中资料 A1 替换成C1C1 替换成B1B1 替换成A1input.dat 档的内容如下:

1
2
3
4
5
6
7
代号
B1
A1
B1
C1
A1
C1

说明: input.dat 档中全部资料行只需要执行一次替换动作 , 但为避免资料被替换多次 , 所以利用函数参数 t 在 sed script 内形成一类似 C 语言中 case statement 结构 , 使每行资料替换一次後能立即用函数参数 t 跳离替换编辑。

sed 命令列:

1
2
3
4
5
6
7
8
sed -e '{
s/A1/C1/
t
s/C1/B1/
t
s/B1/A1/
t
}' input.dat