shell脚本学习指南[一](Arnold Robbins & Nelson H.F. Beebe著)

Categories: 工具语言, 读书
Comments: No Comments
Published on: 2011 年 12 月 28 日

上一页整页的学习了linux下的正则,一般用正则匹配出的数据都是需要用来处理的,这里我们就要学习一下处理这些我们取出的数据的一个命令sed(stream editor)。
语法:sed [ -n ] 'editng command' [file ...]
sed [-n] -e 'editing command' ... [file ...]
sed [-n] -f script-file ... [file ...]
用途:编辑它的输入流,将结果生成到标准输出里。
主要选项:
-e 'editing command'将editing command使用在输入数据上。当有多个命令需要应用时,就必须使用-e
-f script-file 自script-file中读取编辑命令。当有多个命令需要执行时,此选项相当有用。
-n 不是每个最后已修改结果都正常打印,而是显示以p指定(处理过的)的行。
例子:
sed 's/:.*//' /etc/passwd #删除第一个冒号之后的所有内容
sed 's;/home/tolstoy/;/home/lt/;' #修改名称,这里;是定界符。
sed 's/^/mkdir /' #插入mkdir命令
上边第二个例子使用了定界符,也可以不使用,那要转意/符号,如下:
sed 's/\/home\/tolstoy\//\/home\/lt\//' 需要使用\ 来转义/ 。

这里解释一下s,作用是要求正则表达式开始寻找三个/之间的内容替换。默认是找到第一个就替换,如果需要全部替换,再最后一个/后边加g字母。如果要特定的第几个替换则写数字n 如 sed 's/Tolstoy/Camus/2' 第二个Tolstoy替换为Camus。

sed还可以匹配指定范围内的内容,如:
sed -n '10,42p' foo.xml #仅打印10到42行
sed -n '/html/p' *.html #仅显示html这行
sed '/foo/,/bar/ s/baz/quux/g' #仅替换第一个出现foo处到出现第一个bar处范围内的数据。

学了这么多了,再写个shell脚本吧:

#head ----打印前n行
# 语法: head N file
count=$1
sed ${count}q "$2"

迄今为止,我们看到的都是sed以/字符隔开模式以便查找。这里我们看一个使用不同定界符的方法:
$ sed -n '\:tolstoy: s;;Tolstoy;p' /etc/passwd #改变定界符为:号

下边讲一下linux的字段处理。字段用过数据库的应该了解,但是这里指的是文本文件下的字段,怎么理解呢,就是文本文件下,由指定的分界符分隔开的各个字串,每个就是一个字段。这个分界符可以是空格、制表符、分号、冒号等等,选择分界符的原则是字段内不能使用到的一种符号。我们仍然可以打开/etc/passwd文件看一下,这个文件里边的分界符就是冒号,分开的各个字串就是字段了。passwd每个字段的名称也说一下吧:1、用户名称;2、加密后的密码,若帐号停用,此处为一个星号,或是若加密后的密码文件存储另外的/etc/shadow里,则这里也可能是其他字符)。;3、用户ID编号;4、用户组ID编号。5、用户的姓名,有时会另附其他相关数据(办公室号码、电话等)。6、根目录。7、登录的shell。

了解了字段,我们如何在这文本文件里取用字段呢?下边新学习一个命令(感觉这本书挺好的,不单独学习大量的命令,而是学到哪块用到哪个命令就学习哪个命令)。cut,作用是剪下文本文件里的数据,需要注意的是一个制表符被视为一个单个的字符。
语法:cut -c list [ file ...]
cut -f list [ -d delim ] [ file ...]
主要选项:-c list 以字符为主,执行剪下操作。
-d delim 通过选项-f ,使用delim作为定界符。默认的定界符为制表符。
-f list 以字段为主,作剪下的操作。
例子:

$ cut -d : -f 1,5 /etc/passwd #取出1和5字段,定界符为:
$ cut -c 1-10 /etc/passwd #取出1到10个字符,字段也可用-

这个命令简单明了不再赘述,下边跳到经常配合使用的join命令。
语法:join [ options ] file1 file2
用途:以共同一个键值,将已存储文件内的记录加以结合。
主要选项:-1 field1 -2 field2 标明要结合的字段。从第一个文件取出field1和从第二个文件取出field2.字段编号从1开始。
-o file.field 输出file文件中的field字段。一般的字段则不打印。除非使用多个-o。
-t separator 使用separator作为输入字段分隔符,而非使用空白,此字符也为输出的字段分隔符。

这里不要把它想成数据库里外键配合着那要,这里的join只是单纯的按行链接一起,所以想有正确的链接,必须先分别对两个结合文件进行排序。下边给出一个完整shell脚本程序:

#! /bin/sh
#myjoin file1 file2
#删除注释并排序数据文件
sed '/^#/d' $1 | sort > temp1
sed '/^#/d' $2 | sort > temp2
#以第一个键值作结合,结果至标准输出
join temp1 temp2
#删除临时文件
rm temp1 temp2

下边简单介绍一下awk重新编排字段,之后在第九章再介绍该语言精髓。这里简单介绍awk基本概念,随后看到这样的“单命令行程序”就会比较了了解了。
awk的基本模式不同于绝大多数的程序语言,它类似sed:
awk 'program' [ file ...]
awk读取命令行上指定的各个文件(若无,则为标准输入),一次读取一条记录,再针对每行,应用程序所指定的命令。awk程序基本架构为:
pattern { action }
pattern { action }
...
pattern部分几乎可以是任何表达式,但是在单命令行程序里,它通常是由斜杠括起来的ERE。action为任意awk语句,但是单行命令行程序里,通常是一个直接明了的print语句。pattern或是action都能省略(当然,你不会两个都省略把?)。省略pattern则会对每条输出记录执行action;省略action则等同与{ print }。大部分单命令行程序为这样的形式:
... | awk ' { print some-stuff } ' | ...
对每条记录来说,awk会测试程序里的每个pattern。若匹配则执行action。
样例:awk -F: '{ print $1,$5 }' /etc/passwd #定界符为: 打印字段1,5
如果你测试这句,你会发现字段间使用空格隔开的而不是冒号,awk输入输出分隔符是分开限定的。如果要设定输出分隔符,需要对OFS变量赋值,方式是在命令行里使用-v选项,后边可跟着设置awk的变量。例如:
awk -F: -v 'OFS=**' '{ print $1,$NF }' /etc/passwd
上句设定了分隔符**, NF也是awk的一个变量,意思是最后一个字段。另外只写print的话相当于print $0 ,即打印正行。print中间可以夹杂自己想要输出的字符,注意逗号隔开,不然将连接所有字符。也可以使用printf像c程序那样控制输出。awk还有BEGIN和END这两个特殊的模式,他们提供awk程序起始与清除操作。常见于大型awk程序中,且通常写在个别文件里而不是命令行上:

BEGIN { 起始操作程序代码}
pattern1 { action1 }
pattern2 { action2 }
...
END { 清除操作程序代码 }

例如:awk 'BEGIN { FS=":";OFS="**"} { print $1,$5 }' /etc/passwd
大家看到awk的强大的灵活性了把,随后第九章详细介绍awk。

个人原创,转载请注明:三江小渡

我猜你可能也喜欢:

Pages: 1 2 3
No Comments - Leave a comment

Leave a comment

电子邮件地址不会被公开。 必填项已用*标注

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>


Welcome , today is 星期一, 2018 年 07 月 23 日