SHELL 在指定行的前/后插入指定内容

2018/06/06 16:37
阅读数 3.8K

#如果知道行号可以用下面的方法

sed -i '88 r b.file' a.file    #在a.txt的第88行插入文件b.txt

awk '1;NR==88{system("cat b.file")}' a.file > a.file

 

#如果不知道行号,可以用正則匹配

sed -i '/regex/ r b.txt' a.txt # regex是正则表达式

awk '/target/{system("cat b.file")}' a.file > c.file

#sed的話如果不改变源文件,可以去掉-i开关,修改会输出到STDOUT

 

原文件:

[root@xiaowu shell]# cat -n file 

     1  aaaa

     2  bbbb

     3  cccc

     4  dddd

 

现在要在第二行即“bbbb”行的下面添加一行,内容为“xiaowu”

[root@xiaowu shell]# sed '/bbbb/a\xiaowu' file 

aaaa

bbbb

xiaowu

cccc

dddd

 

如果要加两行“xiaowu”可以用一下语句,注意用“\n”换行

[root@xiaowu shell]# sed '/bbbb/a\xiaowu\nxiaowu' file 

aaaa

bbbb

xiaowu

xiaowu

cccc

dddd

 

如果要在第二行即“bbbb”行的上添加一行,内容为“xiaowu”,可以把参数“a”换成“i”

[root@xiaowu shell]# sed '/b/i\xiaowu' file 

aaaa

xiaowu

bbbb

cccc

dddd

 

以上文件中只有一行匹配,如果文件中有两行或者多行匹配,结果有是如何呢?

 

[root@xiaowu shell]# cat -n file 

     1  aaaa

     2  bbbb

     3  cccc

     4  bbbb

     5  dddd

 

[root@xiaowu shell]# sed '/bbbb/a\xiaowu' file 

aaaa

bbbb

xiaowu

cccc

bbbb

xiaowu

dddd

 

由结果可知,每个匹配行的下一行都会被添加“xiaowu”

 

那么如果指向在第二个“bbbb”的下一行添加内容“xiaowu”,该如何操作呢?

可以考虑先获取第二个“bbbb”行的行号,然后根据行号在此行的下一行添加“xiaowu”

 

获取第二个“bbbb”行的行号的方法:

方法一:

[root@xiaowu shell]# cat -n file |grep b |awk '{print $1}'|sed -n "2"p

4

方法二:

[root@xiaowu shell]# sed -n '/bbbb/=' file |sed -n "2"p

4

由结果可知第二个“bbbb”行的行号为4,然后再在第四行的前或后添加相应的内容:

[root@xiaowu shell]# sed -e '4a\xiaowu' file 

aaaa

bbbb

cccc

bbbb

xiaowu

dddd

[root@xiaowu shell]# sed -e '4a\xiaowu\nxiaowu' file 

aaaa

bbbb

cccc

bbbb

xiaowu

xiaowu

dddd

 

 

向指定行的末尾添加指定内容,比如在“ccccc”行的行尾介绍“ eeeee”

 

[root@xiaowu shell]# cat file

aaaaa

bbbbb

ccccc

ddddd

[root@xiaowu shell]# sed 's/cc.*/& eeeee/g' file

aaaaa

bbbbb

ccccc eeeee

ddddd

用Directory替换所有行中的Manager

[root@sishen ~]# sed 's/Manager/Director/' employee.txt

101,John Doe,CEO

102,Jason Smith,IT Director

103,Raj Reddy,Sysadmin

104,Anand Ram,Developer

105,Jane Miller,Sales Director

只把包含Sales的行中的Manager替换为Director

[root@sishen ~]# sed '/Sales/s/Manager/Director/' employee.txt

101,John Doe,CEO

102,Jason Smith,IT Manager

103,Raj Reddy,Sysadmin

104,Anand Ram,Developer

105,Jane Miller,Sales Director

全局标志 g

g代表全局(global)默认情况下,sed会替换每行中第一次出现的original-string,如果你要替换每行中出现的所有original-string,就需要用g

示例 用大写A替换第一次出现的小写字母a

[root@sishen ~]# sed 's/a/A/' employee.txt

101,John Doe,CEO

102,JAson Smith,IT Manager

103,RAj Reddy,Sysadmin

104,AnAnd Ram,Developer

105,JAne Miller,Sales Manager

把所有小写字母a替换为大写字母A

[root@sishen ~]# sed 's/a/A/g' employee.txt

101,John Doe,CEO

102,JAson Smith,IT MAnAger

103,RAj Reddy,SysAdmin

104,AnAnd RAm,Developer

105,JAne Miller,SAles ManAger

注意上述例子会在所有行上进行替换,因为没有指定地址范围

数字标志(1,2,3,·····)

使用数字可以指定original-string出现的次序,只有第n次出现的original-string才会触发替换,每行数字从1开始,最大为512

比如/11会替换每行中第11次出现的original-string

把第二次出现的小写字母a替换为大写字母A

[root@sishen ~]# sed 's/a/A/2' employee.txt

101,John Doe,CEO

102,Jason Smith,IT MAnager

103,Raj Reddy,SysAdmin

104,Anand RAm,Developer

105,Jane Miller,SAles Manager

为了方便以下示例,首先建立如下文件

[root@sishen ~]# vim substitute-locate.txt

locate command is used to locate files

locate command uses datebases to locate files

locate command can also use regex for searching

~

把每行中第二次出的locate替换为find

[root@sishen ~]# sed 's/locate/find/2' substitute-locate.txt

locate command is used to find files

lcaote command uses datebases to locate files

locate command can also use regex for searching

打印标志p(print)

只打印替换后的行

[root@sishen ~]# sed -n 's/John/Johnny/p' employee.txt

101,Johnny Doe,CEO

在之前的数字标志的例子中使用/2来替换第二次出现的locate。第3行中locate只出现了一次所以没有替换任何内容,使用p标志可以只打印替换过的两行

[root@sishen ~]# sed -n 's/locate/find/2p' substitute-locate.txt

locate command is used to find files

locate command uses datebases to find files

[root@sishen ~]#

写标志w

只把替换后的内容写入到out6.txt文件中

[root@sishen ~]# sed -n 's/John/Johnny/w out6.txt' employee.txt

[root@sishen ~]# cat out6.txt

101,Johnny Doe,CEO

把每行中第二次出现的locate替换为find,把替换后的结果保存到文件中,同时显示输入文件所有内容

[root@sishen ~]# sed 's/locate/find/2w out7.txt' substitute-locate.txt

locate command is used to find files

locate command uses datebases to find files

locate command can also use regex for searching

[root@sishen ~]# cat out7.txt

locate command is used to find files

locate command uses datebases to find files

[root@sishen ~]# sed -n 's/locate/find/2w out7.txt' substitute-locate.txt

[root@sishen ~]# cat out7.txt

locate command is used to find files

locate command uses datebases to find files

[root@sishen ~]#

注意加上-n参数就不会输出显示在屏幕上

忽略大小写标志i(ignore)

[root@sishen ~]# sed 's/john/Johnny/' employee.txt

101,John Doe,CEO

102,Jason Smith,IT Manager

103,Raj Reddy,Sysadmin

104,Anand Ram,Developer

105,Jane Miller,Sales Manager

加上-i参数后才可以实现替换

[root@sishen ~]# sed 's/john/Johnny/i' employee.txt

101,Johnny Doe,CEO

102,Jason Smith,IT Manager

103,Raj Reddy,Sysadmin

104,Anand Ram,Developer

105,Jane Miller,Sales Manager

执行命令标志w(excuate)

首先建立文件bash-file.txt

[root@sishen ~]# cat bash-file.txt

/etc/passwd

/etc/group

在bash-file.txt文件中的每行前面添加 ls -l 并打印结果

[root@sishen ~]# sed 's/^/ls -l/' bash-file.txt

ls -l/etc/passwd

ls -l/etc/group

在bash-file文件中的每行前面添加ls -l 并把结果作为命令执行

[root@sishen ~]# sed 's/^/ls -l /e' bash-file.txt

-rw-r--r-- 1 root root 1623 Oct 12 10:23 /etc/passwd

-rw-r--r-- 1 root root 818 Oct 12 10:23 /etc/group

使用替换标志组合

使用g,I,p和w的组合

下面的例子将把每行中出现的所有Manager或manager替换为Directory。然后把替换后的内容打印到屏幕上,同时把这些内容保存到out8.txt文件中

[root@sishen ~]# sed -n 's/manager/Director/igpw out8.txt' employee.txt

102,Jason Smith,IT Director

105,Jane Miller,Sales Director

sed替换命令分界符

首先新建一个文件path.txt

reading /usr/local/bin directory

限制使用sed把/usr/local/bin替换为/usr/bin,在下面的例子中,sed默认的分界符/都被\转义

[root@sishen ~]# sed 's/\/usr\/local\/bin/\/usr\/bin/' path.txt

reading /usr/bin directory

这样虽然实现了替换,但是操作中很繁琐,所以你可以使用任何一个字符(包括字母,但是不建议这样做)

作为sed替换命令的分界符。如 | 或 ^ 或!如

[root@sishen ~]# sed 'sA/usr/local/bin/A/usr/bin/A' path.txt

reading /usr/local/bin directory

[root@sishen ~]# sed 's|/usr/local/bin|/usr/bin|' path.txt

reading /usr/bin directory

[root@sishen ~]# sed 's@/usr/local/bin@/usr/bin/@' path.txt

reading /usr/bin/ directory

[root@sishen ~]# sed 's^/usr/local/bin^/usr/bin^' path.txt

reading /usr/bin directory

[root@sishen ~]# sed 's!/usr/local/bin!/usr/bin!' path.txt

reading /usr/bin directory

结果都一样,看自己喜好了

单行内容以上执行多个命令

下面的例子演示了在模式空间内执行两个替换命令的过程

[root@sishen ~]# sed '{

> s/Developer/IT Manager/

> s/Manager/Director/

> }' employee.txt #注意空格

101,John Doe,CEO

102,Jason Smith,IT Director

103,Raj Reddy,Sysadmin

104,Anand Ram,IT Director

105,Jane Miller,Sales Director

分析第4行执行过程

1. 读取数据:在这一步,sed读取内容到模式空间,此时模式空间的内容为:

104,Ananda Ram,Developer

2. 执行命令:第一个命令,s/Developer/IT Manager/执行后,模式空间的内容为:

104,Anand Ram,IT Manager

现在在模式空间上执行第二个命令s/Manager/Director/,执行后,模式空间内容为:

104,Ananda Ram,IT Director

谨记:sed在第一个命令执行的结果上,执行第二个命令

3. 打印内容:打印当前模式空间的内容,如下

104,Ananda Ram,IT Director

4. 重复循环:移动到输入文件的下一行,然后重复执行第一步,即读取数据

&的作用----获取匹配到的模式

挡在replacement-string中使用&时,它会被替换成匹配到的original-string或正则表达式,这是个很有用的东西

给雇员ID(即第一列的3个数字)加上[ ],如101改成[101]

[root@sishen ~]# sed 's/^[0-9][0-9][0-9]/[&]/g' employee.txt

[101],John Doe,CEO

[102],Jason Smith,IT Manager

[103],Raj Reddy,Sysadmin

[104],Anand Ram,Developer

[105],Jane Miller,Sales Manager

把每一行放进<>中

[root@sishen ~]# sed 's/^.*/<&>/' employee.txt

<101,John Doe,CEO>

<102,Jason Smith,IT Manager>

<103,Raj Reddy,Sysadmin>

<104,Anand Ram,Developer>

<105,Jane Miller,Sales Manager>

分组替换(单个分组)

跟正则表达式中一样,sed中也可以使用分组,分组以\(开始,以\)结束,分组可以用在回溯引用中,

回溯引用即重新使用分组所选择的部分正则表达式,在sed替换命令的replacement-string中和正则表达式中,都可以使用回溯引用,

单个分组

[root@sishen ~]# sed 's/\([^,]*\).*/\1/g' employee.txt

101

102

103

104

105

上面例子中:

l 正则表达式\([^,0]*/)匹配字符串从开头到一个逗号之间的所有字符(并将其放入第一个分组中)

l Replacement-string中的\1将代替匹配到的分组

l g 即是全局标志

下面例子只会显示/etc/passwd的第一列,即用户名

[root@sishen ~]# sed 's/\([^:]*\).*/\1/' /etc/passwd

root

bin

daemon

adm

lp

sync

shutdown

halt

mail

uucp

operator

……

首先建立下面文件,以便使用

[root@sishen ~]# vim number.txt

1

12

123

1234

12345

123456

~

格式化输出,增加可读性

[root@sishen ~]# sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' number.txt

1

12

123

1,234

12,345

123,456

分组替换(多个分组)

可以使用多个\和(\)

划分多个分组,使用多个分组时,需要在replacement-string中使用\n来指定第n个分组,如下面的示例如只打印第一列(雇员ID)和第3列(雇员职位)

[root@sishen ~]# sed 's/^\([^,]*\),\([^,]*\),\([^,*]\)/\1,\3/' employee.txt

101,CEO

102,IT Manager

103,Sysadmin

104,Developer

105,Sales Manager

在这个例子中可以看到,original-string中,划分了3个分组,以逗号分隔

l ([^,]*\)第一个分组,匹配雇员ID

l ,为字段分隔符

l ([^,]*\)为第二个分组,匹配雇员姓名

l ,为字段分割符,上面的例子演示了如何使用分组

l \1代表第一个分组,(雇员ID)

l ,出现在第一个分组之后的逗号

l \3代表第二个分组(雇员职位)

注意:sed最多能处理9个分组,分别用\1至\9表示

交换第一列(雇员ID)和第二列(雇员姓名)

[root@sishen ~]# sed 's/^\([^,]*\),\([^,]*\),\([^,]*\)/\2,\1,\3/' employee.txt

John Doe,101,CEO

Jason Smith,102,IT Manager

Raj Reddy,103,Sysadmin

Anand Ram,104,Developer

Jane Miller,105,Sales Manager

sed专有的替换标志

\l 标志(小写的 L,理解为lower)

当在replacement-string中使用\l标志时,它会把紧跟在其后的字符当作小写字符来处理,如你所知,下面的例子将把John换成JOHNNY:

[root@sishen ~]# sed -n 's/John/JOHNNY/p' employee.txt

101,JOHNNY Doe,CEO

下面的例子将把JOHNNY 中的H换成h

[root@sishen ~]# sed -n 's/John/JO\lHNNY/p' employee.txt

101,JOhNNY Doe,CEO

\L 标志

当在replacement-string中使用\L标志时,它会把后面所有的字符都当小写字符来处理,例如:

在replacement-string中的H前放置了\L 标志,它会把H和它后面的所有字符都换成小写:

[root@sishen ~]# sed -n 's/John/JO\LHNNY/p' employee.txt

101,JOhnny Doe,CEO

\u标志(理解为upper)和\l类似,只不过是把字符换成大写,当在replacemen-string中使用\u标志时,它会把紧跟其后的字符当作大写字符来处理,下面的例子中,replacement-string里面的h前面有\u的标志,所以h将被换成大写的H:

[root@sishen ~]# sed -n 's/John/jo\uhnny/p' employee.txt

101,joHnny Doe,CEO

\U标志

当在replacement-string中使用\U标志时,它会把后面所有的字符都当作大写字符来处理。如下:replacement-string里面的h前面有U的标志,所以h及其后的所有字符都将被换成大写:

[root@sishen ~]# sed -n 's/John/jo\Uhnny/p' employee.txt

101,joHNNY Doe,CEO

\E标志(理解为exit)

\E标志需要和\U或者\L一起使用,他将关闭\U或\L的功能,例如将字符串“Johnny Boy”的每个字符都以大写的形式打印出来,因为在replacement-string前面使用了\U标志

[root@sishen ~]# sed -n 's/John/\UJohnny Boy/p' employee.txt

101,JOHNNY BOY Doe,CEO

下面将把John换成JOHNNY Boy

[root@sishen ~]# sed -n 's/John/\UJohnny\E Boy/p' employee.txt

101,JOHNNY Boy Doe,CEO

因为在Johnny后面使用了\E标志,关闭了\U的功能

替换标志的用法

如下将雇员ID都显示为大写,职位都显示为小写:

[root@sishen ~]# sed 's/\([^,]*\),\([^,]*\),\([^,]*\)/\U\2\E,\1,\L\3/' employee.txt

JOHN DOE,101,ceo

JASON SMITH,102,it manager

RAJ REDDY,103,sysadmin

ANAND RAM,104,developer

JANE MILLER,105,sales manager

这个例子中

l \U\2\3把第二个分组转换为大写,然后使用\E关闭转换

l \L\3 把第三分组转换为小写

mac环境下的几个使用例子:

1、将a.txt中的public request全部替换成public requestUrl
sed -i ".bak" 's/public request/public requestUrl/g' a.txt

2、在a.txt的第66行插入test字符串
sed -i -e '66a \                        //注意此处必须换行
test' a.txt

3、在a.txt中包含public scalar的行下,插入test字符串
sed -i "" '/public scale/a \
test' a.txt

4、在a.txt的第16行插入b.txt内容,例如b.txt在/home/b.txt,则$1即为/home,拼完整路径也可
sed -i ".bak" '16 r '$1'/b.txt' a.txt

5、在a.txt中bb/bb行下,插入c.txt内容
sed -i ".bak" '/bb\/bb/ r c.txt' a.txt

6、只替换首次出现符合条件的字符串,如将a.txt中首次出现value:true的替换为value:false
sed -i ".bak" '1,/value: true/ s/value: true/value: false/' a.txt

7、将a.txt中,每行第2次出现的a替换为A
sed 's/a/A/2' a.txt

 

展开阅读全文
sed
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部