linux从入门到精通读薄(五)sed

linux从入门到精通读薄(五)sed

5-2 修改文件

5-2-1 sed命令

sed是一专门设计的编辑程序,它从标准输入设备接受正文的行,并将它的输出送到标准输出设备上去,在它们通过时,对它们完成编辑。为了使用sed命令,在送入命令时,需要在命令行中指定要完成的编辑操作。由于sed命令只在正文通过它时才能看到正文,它能做的工作是有限度的。

sed命令的标准操作重复地从输入中读入一行,不加改变地送给输出,一直进行到文件结束为止。

如果在命令中指定了编辑操作,只要它是合适的,将在每行读入时进行相应的编辑操作。然后将操作的结果代替原始的输入送给输出。sed命令还对通过它的正文行数进行计数。因此,它可以对特定的行或一段正文进行操作。

通常sed命令从标准输入设备接受输入,如果在命令行中指定一个或多个文件名,它也可以从文件接受输入。

sed命令的格式:

sed actions files

其中actions是编辑操作的清单。如果只有一项操作,可以直接放在命令中。如果需要sed命令完成两项以上的操作,可以有两种选择:在命令行中加入这些操作,每项操作前加上-e开关;或者将这些操作写到一个文件中去,用-f文件开关引导sed去访问这一文件。

有时,需要在正文中指定进行编辑操作的行或行的范围。这可以在每项操作前面给出零个,1个或2个行地址来实现。行地址可以用行号或规则表达式表示。在规则表达式中,又可指定在行中搜索的字符串模式。sed命令使用grep命令的基本规则表达式。

没有行地址的编辑操作适用于输入的正文中的每一行。如果给出一个行地址,则此项操作只适用于特定的行。如果给出两个行地址,则此项操作适用于从第1地址到第2地址之间的所有各行。

仍使用前面的pw.test作例子:

$ cat pw.test | sed "4,$d"
root:awmku76tr43d6:0:0::/root/:/bin/sh
pc:bdhd74hs9jh3h:50:50::/usr1/pc:/bin/bash
carey:esJ9ohd8HH89i:501:50::/usr1/carey:/bin/bash

cat命令用来列出pw.test文件的内容,将它的输出通过管道送给sed命令。由sed命令完成单项编辑操作("4,$d")。加引号是必要的,以免和shell发生冲突。如果你对当前的情况有否必要使用引号有怀疑,从安全出发还是加上引号。本项操作的含义是:从第4行起到文件的最后一行($)全部加以删除。

使sed命令在处理完第3行后退出,能达到同样的效果:

$ sed 3q pw.test
root:awmku76tr43d6:0:0::/root/:/bin/sh
pc:bdhd74hs9jh3h:50:50::/usr1/pc:/bin/bash
carey:esJ9ohd8HH89i:501:50::/usr1/carey:/bin/bash

其中pw.test文件作为sed命令的参数给出,不像上例那样通过管道送给它。

有时,需要抑止将所有经过编辑的行送到标准输出设备的默认操作。可以用-n开关来实现这一点。

用了-n开关后,就明确规定哪些行应在标准设备上输出。这可以用p编辑操作来完成。下面是从文件中送出两行进行显示的例子:

$ sed -n 2,3p pw.test
pc:bdhd74hs9jh3h:50:50::/usr1/pc:/bin/bash
carey:esJ9ohd8HH89i:501:50::/usr1/carey:/bin/bash

再复杂一点的例子。使用字符转换操作(y)。字符转换的基本含义是:指定两个等长的字符串。

在选择的行地址范围内,将行中出现在第1字符串中的每个字符,用第2字符串中的对应字符替换。

在下例中,选择所有包含bash的行。在这些行中将所有的冒号字符转换为下划字符(_),将所有的零用百分号(%)替换:

$ sed /bash/y/:0/_%/ pw.test
root:awmku76tr43d6:0:0::/root/:/bin/sh
pc_bdhd74hs9jh3h_5%%_5%__/usr/pc_/bin/bash
carey_esJ9ohd8HH89i_5%1_5%__/usr1/carey_/bin/bash
……

如果在y操作符前面插入惊叹号(!),则此项操作适用于行地址未被先中的所有各行,而不是选中的各行:

$ sed /bash/y/:0/_%/ pw.test
root:awmku76tr43d6_%_%__/root/:/bin/sh
pc:bdhd74hs9jh3h:50:50::/usr1/pc:/bin/bash
carey:esJ9ohd8HH89i:501:50::/usr1/carey:/bin/bash
……

另一个主要的编辑操作(s)使你能用另一字符串取代用规则表达式指定的字符串:

s/expr/new/flags

其中expr是sed用来搜索的规则表达式,new是用来取代规则表达式的正文,而flags则可以从下面清单中进行选择:

num        一般情况下,只有expr的首次出现才被取代。如果指定了num(0-9),则相应的出现次数都应被取代。
g        如果选用g标志,expr的每次出现都new取代。
p        如选用p标志,将在标准输出设备上显示所有发生取代操作的当前行。
w file  此标志将导致发生取代操作的当前行被追加到指定文件file的最后。如果文件不存在,则建立新文件。

例子(修改pw.test文件,阻止从pc到mot的所有用户进行登录。具体做法是将它们的加密口令移支,用字符串off取代。并将所有修改过的行追加到banned文件中):

$ sed '/^p/,/^m/s/:.............:/: off :/w banned' pw.test
root:awmku76tr43d6:0:0::/root/:/bin/sh
pcff:50:50::/usr1/pc:/bin/bash
careyff:501:50::/usr1/carey:/bin/bash
motff:1500:60::/usr1/mot:/bin/bash
grex:cj8AjoWE8h8fs:1500:60::/usr1/mot:/bin/sh

^字符表示行的开头。所以/^p/,/^m/表示从p开关的行起到m开头的行为止所有各行。另一点要注意的是加密口令总长13个字符,所以,规则表达式:.............:将与被选行中两头包含冒号的13个字符串的首次出现相匹配(即口令字段)。

检查banned文件:

$ cat banned
pcff:50:50::/usr1/pc:/bin/bash
careyff:501:50::/usr1/carey:/bin/bash
motff:1500:60::/usr1/mot:/bin/bash

[例子]
假定系统有了shell程序(/bin/sh和/bin/bash)的新版本,放在/usr/local/bin目录下,需要修改口令文件的shell路径名,使用户去试用新的shell程序:

$ sed 's? /bin/.*sh$? /usr/local&?' pw.test
root:awmku76tr43d6:0:0::/root/:/usr1/pc:/usr/local/bin/bash
carey:esJ9ohd8HH89i:501:50::/usr1/carey:/usr/local/bin/bash
mot:dhjd83kjdJS6D:1500:60::/usr1/mot:/usr/local/bin/bash
grex:cj8AjoWE8h8fs:1500:60::/usr1/mot:/usr/local/bin/sh

规则表达式中包含/字符,常用作替换操作的分隔符。
规则表达式后面的$字符表示在行的结束处进行比较。
替换字符串后面的&字符本身应该用与规则表达式匹配的正文所代替。

[最后一个例子]
在每个用户的登录名后面加下划线,并将登录名carey改为cew:

$ sed -e s/:/_:/ -e/carey./s//cew_/ pw.test
root_:awmku76tr43d6:0:0::/root/:/usr1/pc:/usr/local/bin/bash
cew_:esJ9ohd8HH89i:501:50::/usr1/carey:/usr/local/bin/bash
mot_:dhjd83kjdJS6D:1500:60::/usr1/mot:/usr/local/bin/bash
grex_:cj8AjoWE8h8fs:1500:60::/usr1/mot:/usr/local/bin/sh

在第2项编辑操作中,替换命令后面没有指定规则表达式。在这种情况下,将用行地址中的规则表达式的值或前一替换命令中的表达式来代替这一表达式。
                                                                      (待续)
----------------------------------------------------------------------------------
惨的是发现自己难以弄懂的地方越来越多了,只好如实的记下来(原书是超星pdg格式,不知道linux下该用什么阅览器),到linux下慢慢看、慢慢练习了,所谓的“读薄”怕会成空话了吧……
我也正在看,主要是熟悉命令的用法,多多练习