sed3:地址选择

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CPP_MAYIBO/article/details/84500825


sed中的地址决定了哪些行才会执行sed中的命令。也就是说只有那些指定地址的行才会被sed处理。

概述

  • 地址可以由一个单独的数字指定,下面的命令表示在第144行中,将hello替换为world
sed '144s/hello/world/' input.txt > output.txt
  • 如果不指定地址,那么sed命令默认将会在每一行都执行,下面的命令将会把每一行的hello替换为world。
sed 's/hello/world/' input.txt > output.txt
  • 地址可以是一个正在表达式,下面的命令每一个会在包含apple的行中将hello替换为world
sed '/apple/s/hello/world/' input.txt > output.txt
  • 地址范围可以是由逗号分隔的两个地址组合而成,这里的组合可以是两个数字的组合,可以是正则表达式的组合也可以混合的组合,下面命令是将从第2行到第18行中的hello替换为world
sed '2,18s/hello/world/' input.txt > output.txt
  • 在地址的描述符后(在sed的命令之前)使用 !符号可以取反,也就是将地址描述符所指的地址排除,而剩余地址的内容将被sed命令处理。下面的第一个命令表示将不包含apple的行中的hello替换为world,第二个命令表示将除第二行到第18行以外的所有行的hello替换为world。
sed '/apple/!s/hello/world/' input.txt > output.txt
sed '2,18!s/hello/world/' input.txt > output.txt

通过数字指定地址

前面已经提到过可以使用一个单独的数字来指定特定的行,除此之外还有其他方式。

  • $ 表示输入文件的最后,或者是每一个输入文件的最后一行(当使用 -i 或 -s 选项时)

  • first~ step 表示从行first开始,每隔step行处理一次数据,也就是说sed将会对行号等于 first + (step * n) 的行进行处理。如下示例:

$ seq 10 | sed -n '9~1p'
9
10
 
$ seq 10 | sed -n '9~0p'
9

通过正则表达式来指定地址

  • /regexp/ 表示只有匹配regexp的行会处理,如果regexp中包含有斜杠(/),那每一个斜杠之前都需要使用一个反斜杠(\)进行转义。下面的命令表示将passwd文件中以bash结尾行打印出来:
 sed -n '/bash$/p' /etc/passwd
  • %regexp% (%可以用其他任意的单个字符替换) 该正则表达式的表示方式本质和上面的方式是一样的,主要区别就是分隔符不一样,这里是%。这么做的一个非常有用的原因就是当你的regexp中包含有很多的斜杠(/),使用这种方式就不用在每一个斜杠之前加一个反斜杠了。当然只要在regexp包含了分隔符(比如这里的%),那么在其前面都要使用一个反斜杠。如下几个命令都是等价的:
sed -n '/^\/home\/alice\/documents\//p'
sed -n '\%^/home/alice/documents/%p'
sed -n '\;^/home/alice/documents/;p'
  • /regexp/I
    %regexp%I
    I标识符表示在进行正则匹配的时候将不区分大小写(case-insensitive)。
$ printf "%s\n" a b c | sed '/b/Id'
a
c
 
$ printf "%s\n" A B C | sed '/b/Id'     
A
C

上面的命令中,都是使用小写字母b去进行匹配,由于使用了I标识符,所以字符b将会匹配 B 和 b。
需要补充的是,在很多的其他编程语言中 都是使用字符 i 表示不区分大小写,但由于在sed中 i 是一个命令表示插入数据,所以sed使用 I 来表示不区分大小写。

  • /regexp/M
    %regexp%M
    M标识符使得sed可以在多行模式下进行匹配,也就是说当模式空间中只有一行时该标识符没有任何作用,而如果模式空间中有多行时,该标识符可以使得 M 同时匹配行尾和模式空间的结尾,^可以同时匹配行首和模式空间的头部。不加M时 不能匹配行尾,^不能匹配行首。

最后,正则地址都是作用于当前模式空间的内容上,如果模式空间的内容发生改变,那么正则将会和改变后的内容进行匹配。看如下示例:

$ seq 3 | sed -n 's/2/X/  ;/[0-9]/p'
1
3

上述示例中,命令s/2/X/ 将数字2替换为X,这使得模式空间的内容发生了改变,然后再执行后面的命令是,由于X和[0-9]是不匹配的,所以将不会执行打印操作。

范围地址的表示

前面已经提到过,一个地址范围可以由逗号分隔的两个地址组合而成。
地址范围中如果第二个地址是一个正则表达式,那么它可能会匹配到第一个地址及其之前的地址,这显然这是不合理的;所以匹配是从第一个地址之后开始进行的,匹配到的第一个地址作为地址范围中的第二个地址,如下示例:

$ seq 10 | sed -n '2,/[0-9]/p'
2
3

如果第二地址是一个数字但是小于第一个地址,这时只会匹配一行:

$ seq 10 | sed -n '4,2p' 
4
  • 0,/regexp/ 可以使用0来当做一个地址,0,/regexp/ 表示sed将会从输入的第一行开始处理,这实际上说明 0,/regexp/ 和 1,/regexp/ 的地址范围是相同的,除非/regexp/就只匹配到了第一行,这时地址范围就是 0,1 ,其实也就是第一行(因为输入文件中是没有第0行的),如果使用除此之外的其他方式给某个sed命令指定的行是0,那么将会报错:
$ seq 10 | sed -n '0p'  
sed:-e 表达式 #1,字符 2:非法使用地址0
$ seq 10 | sed -n '0,1p'
sed:-e 表达式 #1,字符 4:非法使用地址0

也就是说只有使用 0,/regexp/ 这种方式才是合法的,下面的示例说明了分别以1和0作为起始地址的区别:

$ seq 10 | sed -n '0,/[0-9]/p'
1
 
$ seq 10 | sed -n '1,/[0-9]/p'
1
2
  • addr1,+N 表示地址范围从 addr1到addr1+N
$ seq 10 | sed -n '1,+3p' 
1
2
3
4
  • addr1,~N 表示地址范围从addr1开始到行数是N的倍数的行
$ seq 10 | sed -n '5,~4p'
5
6
7
8

猜你喜欢

转载自blog.csdn.net/CPP_MAYIBO/article/details/84500825
sed