sed和awk用法扼要

转自:http://www.study-area.org/linux/system/linux_shell.htm

关于sed 的常用命令﹐请参考下表﹕

命令语法说明
aa\ string在字行后面增加特定字串(新行)。
cc\ string将字行换成特定字串。
dd删除字行。
ii\ string在字行前面插入特定字串(新行)。
pp显示字行。除非用-n 指明﹐预设会在处理完毕之后显示子行。
ss/oldstring/newstring/flag

用新的字串替换旧的字串。其中可用的旗标有﹕

g﹕替换行中的所有旧字串(预设只换第一个)﹔

p﹕显示﹔

file ﹕写入特定档案。

例如﹐您要输入﹕

sed 1,3d src.file

所显示的结果﹐就会将src.file 的前面三行砍掉。如果您输入﹕

sed '3,$d' src.file

这样﹐所显示的结果﹐就会从第3 行到最后一行都砍掉﹐只剩下第1 和第2 行而已。上面的命令别忘了加引号﹐否则要\$ 来跳脱。不过﹐我强​​烈建议您用单引号将sed 的命令括起来。如果您要将空白行拿掉﹐用RE 来做非常简单﹕

sed '/^$/d' src.file

在sed 里面引用RE 的时候﹐ 通常都会用两个/ / 符号将RE 括起来﹐然后才是命令。如果您想要更换字串﹐那就要用s 命令了﹕

sed 's/red/blue/g' src.file

这样﹐所有的red 字串都会被换成blue ﹔如果没有加上g 旗标﹐那么只有每一行的第一个red 被替换而已。

除了d 和s 命令之外﹐我们还可以用a 命令在句子后面新增一行﹐内容为字串部份﹔或用i 命令在句子前面插入一行﹐内容为字串部份﹔也可以用c 命令将整行换成字串部份。不过﹐您在执行这几个命令的时候﹐必须要用' ' 将命令和参数括起来﹐然后用\ 符号在命令后面跳脱Enter 键﹐然后才能完成。嗯﹐说起来蛮难理解的﹐不如实作一下吧﹕

sed ' $a \ 
New line appened at the end. ' src.file

这样﹐就会在档案最后面增加一行句子了。再比方说﹐您要将第3 行换成另外的文字﹐可以这样玩﹕

sed ' 3c \ 
The third line is replace with this line. ' src.file

再比方说﹐您想将您存储邮件的档案~/mbox 用虚线分开每一封邮件﹐可以这样试试﹕

sed ' /^From /i 
\
 
------------------------- 

'
 ~/mbox

我想﹐您应该不会忘记我们在前面的文章中﹐用ifconfig | grep | tr | cut 这些命令管线来抓出网路卡的界面吧。事实上﹐我们用sed 命令也一样可以得到同样的结果﹕

ifconfig eth0 | grep "inet addr" | sed -e 's/^.*addr://' | sed 's/ *Bcast.*$//'

第一个sed 是将addr: 到句子前面的字串用s 命令替换为无字串(也就是在最后的// 中间没任何字符)﹔然后第二个sed 将Bcast 连同前面的空白﹐到句子末端也用s 替换为无字串(注意﹕/ *Bcast 的/ 和* 之间是空白键)﹔这样﹐剩下来的就是IP 位址了。

目前﹐我们所进行的命令输出﹐都是在荧幕上﹐既然您已经学会命令的重导向了﹐要将结果保存到其它档案去﹐应是易如反掌了吧。^_^

至于sed 的应用技巧﹐您可以到如下网站好好研究一下﹕

http://www.ptug.org/sed/sedfaq.htm

学习过sed 之后﹐让我们再看看awk 这个命令究竟有什么神通。就拿刚才所举的抓IP 的例子来说好了﹐换成awk 也行哦﹕

ifconfig eth0 | grep "inet addr" | awk -F ' ' '{print $2}' | awk -F ':' '{print $2}'

这里的awk 和cut 命令很相似﹕首先﹐用-F 定义出分隔符号(注意﹕第一个命令用空白做分隔符﹐所以-F 后面的两个' ' 之间是空白键)﹐然后再用print 命令将相应的列抓出来。对awk 而言﹐变数$0 代表每一行被处理的句子﹐然后第一个栏位是$1﹑第二个栏位是$2﹑.... ﹐如此类推。

如果您以为awk 只能做这些事情﹐就实在是太小看它了﹗ 例如您有这样一个文字档(dog.txt)﹐里面只有这么一行文字﹕

The brown fox jumped on the lazy dog​​ quickly.

然后我们用awk 来进行处理﹕

awk '{ $2="black"; $3="dog"; $8="fox"; print}' dog.txt 
The black dog jumped on the lazy fox quickly.

从上面的例子中﹐我们发现awk 具有处理变数的能力﹐事实上﹐它也有自己内建的变数﹕

变数名称代表意思
FS栏位分隔符号(预设是空白键)。
NF当前句子中的栏位数目。
NR当前句子的行数。
FILENAME当前处理的档案名称。

甚至﹐awk 还能进行数值上的比对﹕

变数名称代表意思
>大于。
<小于。
>=大于或等于。
<=小于或等于。
==等于。
!=不等于。

另外﹐如果严格来执行的话﹐awk命令一共分成三个部份﹕ BEGIN ﹑ main ﹑和END。在awk命令中﹐BEGIN的部份﹐是让程式开始时执行一些一次性的命令﹔而END部份则在程式退出的时候执行一些一次性的命令﹔而main呢﹐则以回圈的形式逐行处理输入。一般来说﹐我们无须定义BEGIN和END﹐直接定义main的部份就可以执行awk命令了。例如﹕

echo abcd | awk 'BEGIN { x=1;y=2;z=x+y } {print $x $y $z}' 
abc

这个例子有点多余﹐仅作示范而已。因为﹐我们在BEGIN 定义了x﹑y﹑z 的值﹕( 1﹑2﹑3 )﹐然后我们再将$x﹑$y﹑$z (也就是$1﹑$2﹑$3 ) 的栏位列引出来。所以﹐执行结果是第四栏的d 就没有显示了。

再例如﹐您有一个档案(result.txt)﹐其内容如下﹕

FName LName English Chinese Math
Kenny Chen 80 80 50
Eward Lee 70 90 90
Amigo Chu 50 80 80
John Smith 90 50 75

您可以用下面的命令﹐找出Chinese 及格的名单﹐而只显示其名(忽略其姓)﹕


# awk '{ if ($4 >= 60) print $1" : "$4}' result.txt | tail +2
Kenny : 80
Eward : 90
Amigo : 80

如果您不想显示作为标头的第一行句子﹐可以pipe 到tail 命令进行过滤。不如﹐让我们再玩些更复杂的﹐比方说计算所有名单的平均成绩算﹐并且以最后一列显示出来﹐可以这样设计﹕


# awk '{
total = $3 + $4 + $5
number = NF - 2
average = total/number
if (NR < 2) printf("%s\t%s\n", $0, "AVERAGE");
if (NR >= 2) printf("%s\t%3.2f\n", $0, average)
}' result.txt
FName LName English Chinese Math AVERAGE
Kenny Chen 80 80 50 70.00
Eward Lee 70 90 90 83.33
Amigo Chu 50 80 80 70.00
John Smith 90 50 75 71.67

这个命令看起来有点复杂﹐需要说明一下﹕

  1. 首先﹐我们用一对{ } 将awk 的命令括起来﹐然后在其外面再加一对' ' ﹐这样您可以在单引号之间敲Enter 将长命令分成多行输入。

  2. 然后定义了total 的变数为第3﹑4﹑5 栏的总和(也就是English + Chinese + Math)﹐以及变数number 为栏位数目减掉2 (也就是NF - FName - LName )。

  3. 然后﹐平均值就是total 除以number 。

  4. 因为档案中的第一行是不能用来运算的﹐而且还必须再加上一个叫AVERAGE的栏位标头﹐所以这里首先用一个if来判断行号是否少于2 (不过﹐我在测试的时候﹐发现不能用= 1来设定﹐我也不知道为什么﹖)﹐然则﹐用printf命令(注意﹕在print后面有一个f字母) ﹐以指定格式进行显示。这里的格式是﹕首先是一个字串( %s )﹐也就是后面所对应的$0 (整行句子)以字串格式显示﹔然后是一个tab键( \t )﹔再下来又是一个字串﹐也就后面的"AVERAGE" (非变数值必须用" "括起来)﹔最后输入一个断行符号( \n ﹐newline的意思)。这里﹐您会发现﹐凡是用%表示的格式﹐必须依顺序对应到后面的显示栏位﹔而用\开头的﹐则是可以从键盘输入的符号。(或许﹐刚开始可能比较难看出个所以然﹐多比较一下﹐就不难发现它的规则啦。后面还有一个范例。)

  5. 接下来的﹐会先用if 判断行号是否大于或等于2 (您也可以用> 1 ﹐也就是从第二行开始)﹐然则﹐再用printf 命令﹐按%s\t%3.2f\n的格式来显示。其中的%s﹑\t﹑\n 相信您都知道了﹐只有%3.2f 没见过而已。它定义出浮点数字( floating point )的显示格式是﹕小数点左边3 位数和小数点右边两位数。所以这行的格式是﹕先用字串显示整行﹑然后一个tab 键﹑然后以3.2 小数点格式显示前面定义好的average 变数﹑最后是一个断行符号﹕

                  %s \t %3.2f \n
    | | | |
     Kenny Chen 80 80 50 70.00
    | | | |
                  $0 average
    

  6. 然后是'{ }' 这些括号及引号的​​关闭﹐最后是要处理的档案名称。

而每一行的输出结果﹐就会在字行后面按指定的格式加上tab 键和平均值了。是否很神奇呢﹖ ﹗ 呵呵﹐这只是awk 的牛刀少试而已﹐若要完全发挥awk 的强大火力﹐恐怕已经不是我所能介绍的了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值