-------------sed 查找与替换----------------

在文本文件离进行替换

在很多 shell 脚本的工作都从通过 grep 或 egrep 去除所需的文本开始。正则表达式查找的最初结果,往往就成了要拿来作进一步处理的“原始数据”。通常,文本替换至少需要做一件事,就是讲一些字以另一些字取代,或者删除匹配行的某个部分。

执行文本替换的正确程序应该是 sed----流编辑器。

sed 的设计就是用来批处理而不是交互的方式编辑文件。当药做好几个变化的时候,不管是对一个还是对数个文件,比较简单的方式就是将这些变更部分写到一个编辑的脚本里,再将此脚本应用到所有必须修改的文件,sed 的存在目的就在这里。

在 shell 里,sed 主要用于一些简单的文本替换,所以我们先从他开始。

基本用法:我们经常在管道中间使用 sed,用来执行替换操作,做法是使用 s 命令----要求正则表达式寻找,用替换文本替换匹配的文本呢,以及可选的标志:

sed ‘s’:.*//’ /etcpasswd | 删除第一个冒号之后所有的东西

sort -u 排序列表并删除重复部分

sed的语法:

sed [-n] ‘editing command’ [file...]

sed [-n] -e ‘editing command’ [file...]

sed [-n] -f script-file... [file...]

用途: sed 可删除(delete)、改变(change)、添加(append)、插入(insert)、合、交换文件中的资料行,或读入其它档的资料到文>件中,也可替换(substuite)它们其中的字串、或转换(tranfer)其中的字母等等。例如将文件中的连续空白行删成一行、"local"字串替换成"remote"、"t"字母转换成"T"、将第 10 行资料与第 11 资料合等。

总合上述所言,当 sed 由标准输入读入一行资料并放入 pattern space 时,sed 依照 sed script 的编辑指令逐一对 pattern space 内的资料执行编辑之後,再由 pattern space 内的结果送到标准输出,接着再将下一行资料读入。如此重执行上述动作,直至读完所有资料行为止。

小结,记住:

(1)sed 总是以行对输入进行处理

(2)sed 处理的不是原文件而是原文件的拷贝


主要参数:

-e:执行命令行中的指令,例如:sed -e 'command' file(s)

-f:执行一个 sed 脚本文件中的指令,例如: sed -f scriptfile file(s)

-i:与-e的区别在于:当使用-e 时,sed 执行指令并不会修改原输入文件的内容,只会显示在 bash 中,而使用-i 选项时,sed 执行的指令会直接修改原输入文件。

-n:读取下一行到 pattern space。

行为模式:

读取输入文件的每一行。假如没有文件的话,则是标准输入。以每一行来说,sed 会执行每一个应用倒数入行的 esiting command。结果会写到标准输出(默认情况下,或是显式的使用 p 命令及-n 选项)。若无-e 或-f 选项,则 sed 会把第一个参数看做是要使用的 editing command。


find  /home/tolstoy  -type -d -print // 寻找所有目录  

sed ‘s;/home/tolstor;/home/lt/;’ // 修改名称;注意:这里使用分号作为定界符  

sed ‘s/^/mkdir /’ `//插入 mkdir 命令  

sh -x`                           //以 shell 跟踪模式执行

上述脚本是说将/home/tolstoy 目录结构建立一份副本在/home.lt 下(可能是为备份)而做的准备


替换案例:

Sed 可替换文件中的字串、资料行、甚至资料区。其中,表示替换字串的指令中的函数参数为s;表示替换资料行、或资料区>的指令中的函数参数为c。上述情况以下面三个例子说明。


行的替换

sed -e '1c/#!/bin/more' file (把第一行替换成#!/bin/more)

思考:把第 n 行替换成 just do it

sed -e 'nc/just do it' file

sed -e '1,10c/I can do it' file (把 1 到 10 行替换成一行: I can do it)

思考:换成两行(I can do it! Let's start)

sed -e '1,10c/I can do it!/nLet'"/'"'s start' file

字符的替换

$ sed 's/test/mytest/g' example-----在整行范围内把 test 替换为 mytest。如果没有 g 标记,则只有每行第一个匹配的 test 被替换成 mytest。

$ sed -n 's/^test/mytest/p' example-----(-n)选项和 p 标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的 test 被替换成 mytest,就打印它。

$ sed 's/^192.168.0.1/&localhost/' example-----&符号表示替换换字符串中被找到的部份。所有以 192.168.0.1 开头的行都会被替换成它自已加 localhost,变成 192.168.0.1localhost。

$ sed -n 's/loveable/\1rs/p' example-----love 被标记为 1,所有 loveable 会被替换成 lovers,而且替换的行会被打印出来。

$ sed 's#10#100#g' example-----不论什么字符,紧跟着 s 命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有 10 替换成 100。


替换与查找

在 s 命令里以 g 结尾表示的是:全局性,意即“替代文本取代正则表达式中每一个匹配的”。如果没有设置 gsed 指挥取代第一个匹配的。


鲜为人知的是:可以在结尾指定数字,只是第 n 个匹配出现才要被取代:

sed ‘s/Tom/Lisy/2’ < Test.txt 仅匹配第二个 Tom

通过给 sed 增加一个-e 选项的方式能让 sed 接受多个命令。

sed -e ‘s/foo/bar/g’ -e ‘s/chicken/cow/g’ myfile.txt 1>myfile2.txt

用 shell 命令将 test.log 文件中第 3-5 行的第 2 个“filter”替换成“haha”

sed -i '3,5s/filter/haha/2' test.log


下面介绍所有 sed 的函数参数的功能(editing command)。

= 印出资料行数( line number )。


a :添加使用者输入的资料。

b :label 将执行的指令跳至由 : 建立的参考位置。

c :以使用者输入的资料取代资料。

d :删除资料。

D :删除 pattern space 内第一个 newline 字母 前的资料。

g :拷贝资料从 hold space。

G :添加资料从 hold space 至 pattern space 。

h :拷贝资料从 pattern space 至 hold space 。

H :添加资料从 pattern space 至 hold space 。

l :印出 l 资料中的 nonprinting character 用 ASCII 码。

i :插入添加使用者输入的资料行。

n :读入下一笔资料。

N :添加下一笔资料到 pattern space。

p :印出资料。

P :印出 pattern space 内第一个 newline 字母 前的资料。

q :跳出 sed 编辑。

r :读入它档内容。

s :替换字串。

w :写资料到它档内。

x :交换 hold space 与 pattern space 内容。

y :转换(transform)字元。


---sed 正则的精确控制----------

有多少文本会改动

在使用 sed 的时候我们来看这么两个问题:第一个问题是有多少人文本会匹配,第二个问题是从哪里开始匹配。

回答是:正则表达式可以匹配整个表达式的输入文本中最长的,最左边的子字符串。除此之外,匹配的空(null)字符串,则被认为是比完全不匹配的还长.

echo syx is a good body | sed ‘s/syx/zsf/’ 使用固定字符串

sed 可以使用完整的正则表达式.但是应该知道”从最长的最左边”规则的重要性.


echo Tolstoy is worldly | sed ‘s/T.*y/Camus/’

Camus

很明显,我们只想要匹配 Tolstoy,但是由于匹配会扩展到可能的最长长度的文本量,所以出现了这样的结果.


这就需要我们精确定义:

echo Tolstoy is worldly | sed ‘s/T[[:alpha:]]*y/Camus/’

Camus is worldly

在文本查找中,有事喊可能会匹配到 null 字符串,而在执行文本替代时,也允许插入文本.


ehco abc | sed ‘s/b*/l/’ 

labc  

ehco abc | sed ‘s/b*/l/g’  

lalcl  

请留意,b*shi 如何匹配 abc 的前面与结尾的 null 字符串.


------行与字符串-------

行 V.S.字符串

大部分建议等程序都是处理输入数据的行,在这些情况下,不会有内嵌的换行字符出现在将要匹配的数据中,^与$则分别表示行的开头与结尾.


很多应用程序会将数据是位记录与字段的结合.一条记录指的是相关信息的翻个集合,例如以企业来说,记录可能含有顾客,供应商以及员工等数据,以学校来说,则可能有学生数据.而字段指的就是记录的组成部分,例如姓名或者街道地址.


linux 鼓励使用文本类型数据,因此系统上最常见的数据存储类型就是文本了,在文本下,一行表示一天记录.一行内分割字段的两种惯例是:

第一种:空格或者 tab 键(制表符).

name sex

syx M

第二种是使用特定的定界符来分割字段,例如冒号

name:sex

syx:M

两种方式各有优缺点.最明显的不同时是在处理多个连续重复的戒定福之时.使用空白分隔时,通常多个连续出现的空格或制表字符都看做一个定界符.濡染,若使用的特殊字符分隔,则每个定界符都会隔开一个字段.


以定界符分割字段最好的例子就是/etc/passwd,在这个文件里,一行标识系统的一个用户,每个字段都是以冒号分隔.


syx5:x:511:513::/home/syx5:/bin/bash.


该文件含有七个字段,含义分别如下


1:用户名称

2:加密后的密码(如账号为停用状态,此处为一个星号,或者若加密后的密码 文件存储于另外的/etc/shadow 里,则这里可能是其他字符)

3:用户的 ID 编号

4:用户组的 ID 编号

5:用户的姓名,有时恢复其他的相关数据(电话号,办公室号码)

6:根目录

7:登陆的 shell


-----------sed 案例分析------------------

sed 的使用案例

使用 sed 操作/etc/passwd,最好复制一份(cp /etc/passwd /tmp),操作 tmp 下的 passwd(其实不用,因为在一般情况下 sed 只是修改了输出结果,不会改变文件本身,除非要求这么做).


以行为单位的新增/删除

要求:将/etc/passwd 的内容列出并且列印行号,同时删除 2~5 行.

做法:cat /etc/passwd | sed ‘2,5d’

sed 的动作是’2,5d’(动作需要放在单引号之间)

nl 命令在 linux 系统中用来计算文件中行号。nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等等的功能。

只删除第二行:

nl /etc/passwd | sed ‘2d’


删除第3行到最后一行

cat -n /etc/passwd | sed ‘3,$d’


在第二行后(就是在第三行)加上”i am fine”字样

cat -n /etc/passwd | sed ‘2a i am fine’


如果要在第二行前面

nl /etc/passwd | sed ‘2i i am fine’


如果是要增加两行以上,在第二行后面加入两行字,例如『hello』与『how are you』

nl /etc/passwd | sed ‘2a hello\

>how are you’

每一行之间都必须要以反斜杠()来进行新行的添加,所以上面的例子,我们可以发现在第一行的最后面就有 \ 存在。

(再输入的是会需要注意,单引号不要一起输完).


以行为单位的替换与现实

将第 2-5 行的内容替换成”hahaha”

nl /etc/passwd | sed ‘2,5c hahaha’

通过这个方法,我们就可以替换整行数据了.


仅列出/etc/passwd 文件的 5-7 行

cat -n /etc/passwd | sed -n ‘5,7p’

可以透过这个 sed 的以行为单位的显示功能, 就能够将某一个文件内的某些行号选择出来显示。


数据的搜寻与显示

搜索/etc/passwd 中有关/root 关键字的行

nl /etc/passwd | sed ‘/root/p’

思考:为什么会输出所有行的情况?

使用-n 的时候将只打印包含模板的行。

nl /etc/passwd | sed -n ‘/root/p’


数据的搜索与删除

删除/etc/passwd 所有包含 root 的行,其他行输出

nl /etc/passwd | sed ‘/root/d’


数据的搜索并执行命令

搜索/etc/passwd,找到 root 对应的行,执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把 bash 替换为 blueshell,再输出这行:

nl /etc/passwd | sed -n '/root/{s/bash/blueshell/;p}'

如果只替换/etc/passwd 的第一个 bash 关键字为 blueshell,就退出

nl /etc/passwd | sed -n '/bash/{s/bash/blueshell/;p;q}' 1

最后的 q 是退出。


数据的搜索并替换

除了整行的处理模式之外,sed 还可以用行为单位进行部分数据的搜寻并替换.基本上 sed 的搜寻与替换与 vi 相当的类似.

sed ‘s/要被取代的字符串/新的字符串/g’


先通过/sbin/ifconfig eth0 查看本机的 IP 地址,我的是(192.168.199.5)

将 IP 前面部分予以删除

/sbin/ifconfig eth0 | grep 'inet addr'|sed 's/^.*addr://g'

将 IP 后面部分予以删除

/sbin/ifconfig eth0 | grep 'inet addr'|sed 's/^.*addr://g' | sed 's/Bcast.*$//g'

即可得到 IP


多点编辑

一条 sed 命令,删除/etc/passwd 第三行到末尾的数据,并把 bash 替换成 hahaha.

nl /etc/passwd | sed -e ‘3,$d’ -e ‘s/bash/hahaha/g’

注意:每天命令前面都加入了-e 选项


直接修改文件内容

最好别使用,如果使用需要加入一个-i 选项

例如在最后一行插入 hahaha