跟散仙学shell编程(九)

上篇散仙说了如何在linux里面构建更好的交互式shell,本篇来看下linux里面的文本处理工具sed和gawk,在linux里面最常用的就是这两个命令。

sed编辑器是一个流编辑器,与vim交互式的编辑器不同,sed编辑器需要提前提供一组规则来编辑数据流。

sed的命令格式如下sedoptionsscriptfile

(1)-escript在处理输入时,将script中指定的命令添加到运行的命令中

(2)-ffile在处理输入时,将file中指定的命令添加到运行的命令中

(3)-n不要为每个命令生成输出,等待print命令来输出

[search@h1 819]$ echo "this is a test" | sed 's/test/big test/'
this is a big test
[search@h1 819]$

在上例中,s命令,会用斜线间指定的第二个文本字符串来替换第一个文本字符串,下面看下如何对一个文件修改替换:

[search@h1 819]$ cat abc.txt 


this is cat
this is a cat 
this is a big cat
this is cat
[search@h1 819]$ sed 's/cat/dog/' abc.txt 


this is dog
this is a dog 
this is a big dog
this is dog
[search@h1 819]$

sed编辑器,并不会修改原来的文件,只会将修改后的数据发送到STDOUT,如果你查看原来的文件,会发现原来的数据还存在。

下面在来看下如何在sed里面使用多个sed命令:

[search@h1 819]$ cat abc.txt 


this is cat
this is a cat 
this is a big cat
this is cat
[search@h1 819]$ sed -e 's/ is/ are/; s/cat/dog/' abc.txt 


this are dog
this are a dog 
this are a big dog
this are dog
[search@h1 819]$

注意is和are的空格,有时候,不生效,可以加个空格测试!

我们也可以将脚本,放在一个文件里,来使用:

[search@h1 819]$ cat abc.txt 


this is cat
this is a cat 
this is a big cat
this is cat
[search@h1 819]$ cat script 
s/cat/dog/
s/ is/ are/
[search@h1 819]$ sed -f script abc.txt 


this are dog
this are a dog 
this are a big dog
this are dog
[search@h1 819]$

下面介绍下gawk,sed有自身的限制,所以gawk可以很好弥补这个缺点,gawk是Unix中原始的awk程序的GNU版本,gawk让流编辑迈上了一个新的台阶,它提供了一种编程语言,而不只是编辑命令,在gawk中,你可以:

(1)定义变量保存数据

(2)使用算术和字符串操作符来处理数据

(3)使用结构化编程概念,比如if-then语句和循环,来数据处理,增加逻辑

(4)提取数据文件中的数据元素,并将他们按另一顺序重新放置,从而生成格式化报告

gawk的命令格式:

gawkoptionsprogramfile

1,-Ffs指定行中分隔数据字段分隔符

2,-ffile指定读取的文件名

3,-vvar=value定义gawk程序中的一个变量和默认值

4,-mfN指定要处理数据文件中的最大字段数

5,-mrN指定数据文件中最大数据行数

6,-Wkeyword指定gawk的兼容模式或警告等级

gawk程序脚本用一对花括号,来定义,你必须将脚本命令放在两个括号里,由于命令行假设脚本是单个字符串,所以你必须将脚本放在单引号里面:

[search@h1 819]$ gawk '{ print "我是第一个gawk程序! "}'
a
我是第一个gawk程序! 
a
我是第一个gawk程序! 
a
我是第一个gawk程序

当写完这个脚本时,直接回车运行,你会失望,因为你没有指定任何文件,默认是从控制台读入数据的,只有你输入一行数据,按回车,它才会打印,退出可以使用Ctrl+D命令来退出!

gawk的数据字符变量,默认情况下:

$0代表整个文本行

$1代表文本行里面的第一个字段

$2代表文本行里面的第二个字段

$n代表文本行里面的第n个字段

当它在读取以行文本时,默认的分隔符,是任意的空白字符,也就是空格:

[search@h1 819]$ cat abc.txt 


this is cat
this is a cat 
this is a big cat
this is cat
[search@h1 819]$ gawk  ' { print $1 }' abc.txt 


this
this
this
this
[search@h1 819]$

下面看下指定分隔符的例子:

[search@h1 819]$ gawk -F: ' { print $1}    '  /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
operator
games
gopher
ftp
nobody
vcsa
saslauth
postfix
sshd
mysql
search
[search@h1 819]$

下面看下如何使用多个命令:

[search@h1 819]$ echo "my name is solr"  | gawk  '{  $4="hadoop"; print $0  }'
my name is hadoop
[search@h1 819]$

下面看下,如何将gawk程序,存储在文件里,并从文件里执行:

[search@h1 819]$ cat script2 
{ print $1  "'s 目录是 " $6  }
[search@h1 819]$ gawk -F: -f script2  /etc/passwd
root's 目录是 /root
bin's 目录是 /bin
daemon's 目录是 /sbin
adm's 目录是 /var/adm
lp's 目录是 /var/spool/lpd
sync's 目录是 /sbin
shutdown's 目录是 /sbin
halt's 目录是 /sbin
mail's 目录是 /var/spool/mail
uucp's 目录是 /var/spool/uucp
operator's 目录是 /root
games's 目录是 /usr/games
gopher's 目录是 /var/gopher
ftp's 目录是 /var/ftp
nobody's 目录是 /
vcsa's 目录是 /dev
saslauth's 目录是 /var/empty/saslauth
postfix's 目录是 /var/spool/postfix
sshd's 目录是 /var/empty/sshd
mysql's 目录是 /var/lib/mysql
search's 目录是 /home/search
[search@h1 819]$

也可以在程序里面指定多个命令,如果这样,只需要将每个命令放新的行即可:

[search@h1 819]$ cat s3 
{
text = "的目录是 "
print $1 text $6


}
[search@h1 819]$ gawk  -F: -f s3  /etc/passwd
root的目录是 /root
bin的目录是 /bin
daemon的目录是 /sbin
adm的目录是 /var/adm
lp的目录是 /var/spool/lpd
sync的目录是 /sbin
shutdown的目录是 /sbin
halt的目录是 /sbin
mail的目录是 /var/spool/mail
uucp的目录是 /var/spool/uucp
operator的目录是 /root
games的目录是 /usr/games
gopher的目录是 /var/gopher
ftp的目录是 /var/ftp
nobody的目录是 /
vcsa的目录是 /dev
saslauth的目录是 /var/empty/saslauth
postfix的目录是 /var/spool/postfix
sshd的目录是 /var/empty/sshd
mysql的目录是 /var/lib/mysql
search的目录是 /home/search
[search@h1 819]$

在数据处理前,执行某个命令:

[search@h1 819]$ gawk  'BEGIN { print "你好,hadoop" }'
你好,hadoop
[search@h1 819]$

执行这个命令不需要等待,控制台输入

[search@h1 819]$ gawk  'BEGIN { print "开始读取了:"  } {print $0 }  END { print "打印结束了"} '  abc.txt 
开始读取了:


this is cat
this is a cat 
this is a big cat
this is cat
打印结束了
[search@h1 819]$

多个命令之间,用大括号分开即可!

[search@h1 819]$ cat s
BEGIN {

print "我们要加个列头"
print "用户ID     shell "
print "-------      ------"
FS=":"
}


{

print $1 "      " $7

}

END {

print  "结束了....."

}
[search@h1 819]$ gawk  -f s /etc/passwd
我们要加个列头
用户ID     shell 
-------      ------
root      /bin/bash
bin      /sbin/nologin
daemon      /sbin/nologin
adm      /sbin/nologin
lp      /sbin/nologin
sync      /bin/sync
shutdown      /sbin/shutdown
halt      /sbin/halt
mail      /sbin/nologin
uucp      /sbin/nologin
operator      /sbin/nologin
games      /sbin/nologin
gopher      /sbin/nologin
ftp      /sbin/nologin
nobody      /sbin/nologin
vcsa      /sbin/nologin
saslauth      /sbin/nologin
postfix      /sbin/nologin
sshd      /sbin/nologin
mysql      /bin/bash
search      /bin/bash
结束了.....

上面简单的几个例子,gawk使用起来非常给力!

上面散仙简单介绍了sed的命令,下面来看下sed更多的参数:

s/pattern/replacement/flags

最后的参数可以有如下:

数字代表替换第几处的地方

g代表全局替换所有的地方

p表示将内容打印出来

wfile将替换结果写入一个文件

[search@h1 819]$ cat t.txt 
this name is name

this name is hadoop
[search@h1 819]$ sed 's/name/hadoop/2' t.txt 
this name is hadoop

this name is hadoop
[search@h1 819]$ sed 's/name/solr/2' t.txt       
this name is solr

this name is hadoop
[search@h1 819]$

全局替换:

[search@h1 819]$ cat t.txt 
this name is name

this name is hadoop
[search@h1 819]$ sed 's/name/solr/g' t.txt 
this solr is solr

this solr is hadoop
[search@h1 819]$
[search@h1 819]$ cat t.txt 
this name is name

this name is hadoop
[search@h1 819]$ sed 's/name/solr/p' t.txt 
this solr is name
this solr is name

this solr is hadoop
this solr is hadoop
[search@h1 819]$ sed -n  's/name/solr/p' t.txt 
this solr is name
this solr is hadoo

-n命令会禁止sed编辑输出,-p会替换标记输出修改的行

-w会将修改存入一个新文件:

[search@h1 819]$ sed   's/name/solr/w tt' t.txt    
this solr is name

this solr is hadoop
[search@h1 819]$ cat tt 
this solr is name
this solr is hadoop
[search@h1 819]$

如果遇到特殊的字符,则需要转义,使用/进行转义,这个在各种编程语言里都是这样。

在sed里面可以使用!符作为分隔,例如:/bin/bash!/bin/csh!

sed支持更灵活的字符操作:

可以使用行寻址:

例如:sed'2s/dog/cat/'data1这个例子只会改变第二行的数据

sed'2,4s/dog/cat/'data1这个代表一个范围

如果不知道到底多少行可以使用

sed'2,$s/dog/cat/'data1代表以2开头,所有的行

下面看下sed的删除命令:

sed'd3'file代表删除某个文件的第3行,如果什么也不加,则会删除所有

也可以指定范围删除sed'2,3d'file

或者某个范围到结尾删除sed'3,$d'file

此外也可以在查找中删除:

sed'/number1/d'file代表删除number1所在的行

下面看下插入和附加文本:

插入insert

追加append

插入

[search@h1 819]$ echo "1" | sed 'i\"one"'
"one"
1
[search@h1 819]$

追加命令:

[search@h1 819]$ echo "line2" | sed 'a\ line3'
line2
 line3
[search@h1 819]$

插入同样可以指定行数前面:

sed'3i\sometext'会插入在第三行前面

sed'3a\sometext'会拼接在第三行后面

怎么才能直接追加到最后一行:

sed'$a\sometext'

下面看下修改行:

sed'3c\这是修改的行'

sed '3i\some text' 会插入在第三行前面

也可以在查询中修改

sed'/number3/c\sometext'

也可以在地址区间修改sed'2,3c\sometext'

除以之外,还有一个转换命令y:

[search@h1 819]$ echo "this 1 a test of 1 try" | sed 'y/123/456/'
this 4 a test of 4 try
[search@h1 819]$

另外,在sed中,p命令可以打印文本行

=号可以打印行号

l命令用来列行

[search@h1 819]$ echo "test a test" | sed 'p'
test a test
test a test
[search@h1 819]$ echo "test a test" | sed '='
1
test a test
[search@h1 819]$

-n命令可以用来禁止其他的行,只显示匹配上的行

sed-n'/number/p'file

sed-n'2,3p'file

查找含数字3的行,然后执行两条命令,打印当前行,然后替换在打印

sed -n '/3{p s/ is/ test/p }' bb

l命令会列出行

[search@h1 819]$ sed -n 'l' bb
this is 3 txt$
this is 4 text$
this is a text$
this name hadoop$
[search@h1 819]$

sed-n'1,3wtest'file代表将文件file的1-3行的数据写入test文件里面,=n参数代表在写入过程中,不会将输出流在控制台显示

另外sed'3rdata12'data7代码从data7里面读入前行文件插入到data12里面

同样在查询时,也使用sed'/number2/rdata12'data7

在文本末尾添加数据:

sed'$rdata12'data7

相关推荐