SDB:Sed和AWK
目录
定义
- Sed : 处理纯文本流的文本编辑器。
- AWK : 一种输出格式化语言。
起先不用过分纠结于概念,实践几次以后就会有点体会了。越多的使用它就会对它理解的更深。现在不妨先跳过它。回头再来看这个定义。
Sed
Sed可以用来处理文件,我们来举个实际的例子。
首先我们来创建两个文件,随便用什么工具,Kate啊,vim啊,gvim啊都可以,如果你在学习vim正好这也是个应用的机会。
下面我用touch,echo和重tee来创建两个文件,这样做没什么方便的,纯粹就是为了熟悉命令。
首先创建三个个空文件。
touch one.txt two.txt three.txt
给两个空文件分别加入内容
echo -e "a\nb\nc\nd\n" | tee ./one.txt
echo是终端打印的命令,-e选项是说在字符中会使用到转义符号,就是这里的\n了,学过c的同学知道它和c是一样的。甚至你可以这样
printf "d\ne\nf\ng\n" | tee ./two.txt
这就和c更像了。上面的命令可以把内容加入two这个文件中。其中|是通道,将echo和printf的输出传递给tee,而tee的作用是,不仅在终端打印数据,还会把数据输送到文件。如果希望添加而不是不是覆盖可以加上选项 -a
echo -e "a\nb\nc\nd\n" | tee -a ./two.txt
然后我们使用下面命令
sed -e s/a/z/g one.txt two.txt > three.txt
你可以用cat来查看内容
cat ./three.txt
输出如下
z b c d d e f g
我们可以这样理解sed,它把指定的一些文件或输入用一组命令来处理,然后输出到标准输出中。
在这里,指定的文件就是one.txt 和two.txt,而处理的命令就是 s/a/z/g,标准输出就是终端输出,在这里我们通过重定向将它定向到了一个文件里。
我们来看看这个命令,熟悉vim的同学会发现它和vim是一样的,就是搜索和替换,就是把a替换成z,/g的意思是整行的替换,去掉这个只会替换在一行里找到的第一个。当然,在这个例子里是没有影响的。
其实sed的命令可以有多个,比如
sed -e 's/a/z/g; s/b/y/g' one.txt two.txt > three.txt
再用cat看看输出,发现了么,这里的用把命令扩起来,用分号分割不同的命令,其实,只有一个命令的时候也建议你用,这样可以更清楚。
sed还可以多行记录
sed ' >s/a/z/ >s/b/y/ ' one.txt two.txt
其实sed最方便的还是可以把命令写进文件里,这样就可以重复利用,不用每次都敲那么多代码了。
创建一个文件,这次我们用vim好了
vim edits.sedscr s/a/z/ s/b/y/
然后sed -f edits.sedscr one.txt two.txt > three.txt
AWK
AWK的用法和sed其实非常的相似。同样的,他是输入一个命令或一组命令或是写着命令的文件,以及数据或写着数据的文件。然后格式化后输出。
我们来举个实际点的例子。比如我们要提取/etc/passwd里的信息,我们知道这个文件里储存的是用户的资料,电脑通过字段可以很轻松的识别,可是对于系统的管理者来说就没那么方便了,本身记忆那么多字段也是一种负担,现在我们就通过awk来处理这些信息使其变得清晰。
注意此命令要在root后实用,不是所有人都有权限查看/etc/passwd文件的。
#awk -F":" '{print "usrename:" $1 "\t\t\t user ID:" $3}' /etc/passwd
下面是我的部分输出。
usrename:at user ID:25 usrename:avahi user ID:487 usrename:bin user ID:1 usrename:daemon user ID:2 usrename:dhcpd user ID:491 usrename:dnsmasq user ID:488 usrename:fetchmail user ID:481 usrename:ftp user ID:40 usrename:ftpsecure user ID:482 usrename:games user ID:12 usrename:gdm user ID:480
同样的被扩起来的是命令,其中我们知道在passwd文件中第一个字段是用户名,第三个字段是用户ID,默认awk是以空格作为划分字段的依据的。使用了 -F":"后就改成了以:作为划分的依据了。
同样的AWK的命令可以写进文件
vim print.awk
BEGIN{ FS=":" } {printf "\nusername:" $1 "\t\t\t user ID:" $3} END{ printf "\ndone\n" }
然后运行
awk -f print.awd /etc/passwd
你可以看到和上面差不多的输出,其中BEGIN和END的内容只会被执行一次,在这个例子中END的用途只是打印了一个done,告诉你已经执行完成了。 你完全可以去掉它。
与正则表达式结合
但是很多时候并不那么简单,比如,分隔符也许非常的多样,有时虽然机器的输出是格式化的,但是也需要一些智慧去分析,很多时候它会和正则表达式结合,在这里只举一个简单的例子。假设/etc/passwd分隔符有:和,两种(当然这不是真的)。这个时候你可以这样
#awk -F"[:,]" '{print "usrename:" $1 "\t\t\t user ID:" $3}' /etc/passwd
从这个例子你可以窥见,AWK可以编写很复杂的命令来处理复杂的数据,这也许就是为什么我们会说编写AWK程序了。有时它确实就像是一个程序。
关于正则表达式的内容请参看相关的wiki。