在shell脚本中处理任何类型的数据,使用 sed gwak
自动的处理文本文件中的文本。。
=====
sed编辑器:
又称作流编辑器( stream editor ),跟普通交互式文本编辑器恰好相反。在交互式编辑器如(vim)里,你可以使用键盘命令来交互式插入,删除或者替换数据中的文本。刘编辑器则会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。。
sed编辑器可以基于输入到命令行的或是存储在命令文本文件中的命令来处理数据流中的数据。 它每次从输入中读取一行,用提供的编辑器命令 匹配数据,按命令中指定的方式修改流中的数据,然后将生成的数据输出到stdout。 在 流编辑器 将所以命令与一行数据进行匹配后,他会读取下一行命令并重复这个过程。。在流编辑器将流中的所有数据处理完后,它就会终止。。
所以,命令都是一行一行的,而且必须一次就完成对文本的修改,所以速度快。。
sed格式:
sed options script file
options:
-e script 在处理输入时,将script中指定的命令添加到运行的命令中
-f file 在处理输入时,将file中指定的命令添加进运行的命令中
-n 不要为每个命令生成输出,等待print命令来输出。。
script参数指定了将作用在流数据上的单个命令。如果需要用多个命令,你必须用-e 选项来在命令行上指定他们,或用-f 选项来在单独的文件中指定。有大量的命令可以用来处理数据。
----------
1.在命令行使用sed
默认情况下,sed编辑器会将指定的命令应用到stdin输入流。
[oh@localhost shell]$ echo "this is a test" | sed 's/test/sed test/'
this is a sed test
[oh@localhost shell]$
在这里,我使用了管道, sed里,使用s命令:s/aa/bb/ 用bb替换所有的aa
[oh@localhost shell]$ cat testfile
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$ sed 's/this/that/' testfile
that is the first line
This is a test
ond line
that is the third line
that is the end line
[oh@localhost shell]$
速度很快的。
[oh@localhost shell]$ cat testfile
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$ sed 's/this/that/' testfile
that is the first line
This is a test
ond line
that is the third line
that is the end line
[oh@localhost shell]$ cat testfile
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$
可以看到这样做对原文件没有影响。。。sed只会将修改后的数据发送到stdout里。。
现在我想在命令行里使用多个sed语句:
使用-e选项
sed -e 's/bra/under/;s/asd/er/' file
[oh@localhost shell]$ cat testfile
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$ sed -e 's/this/that/; s/is/are/' testfile
that are the first line
Thare is a test
ond line
that are the third line
that are the end line
[oh@localhost shell]$
命令之间用;号分隔,头跟尾部不要有空格
当然你也可以使用shell中的次提示符:> 而不用使用分号;
[oh@localhost shell]$ sed -e '
> s/this/that/
> s/is/are/
> '
testfile
testfile
注意一定要在‘ 号那行结束命令。。bash shell一旦现封尾的单引号。。
所以上面是错误的
[oh@localhost shell]$ sed -e '
> s/th/aa/
> s/is/yu/
> ' testfile
aayu is the first line
Thyu is a test
ond line
aayu is the third line
aayu is the end line
[oh@localhost shell]$
这样才行。。。。
=======
从文件中读取编辑命令
也就是将好多sed处理的命令放在在一个文件里。
[oh@localhost shell]$ cat sedd
s/this/that/
s/is/are/
[oh@localhost shell]$
就是这么随意。。 命令的结束也没有分号。。
然后: sed -f sedd testfile
[oh@localhost shell]$ cat sedd
s/this/that/
s/is/are/
[oh@localhost shell]$ sed -f sedd testfile
that are the first line
Thare is a test
ond line
that are the third line
that are the end line
[oh@localhost shell]$
=========
先介绍一下:gawk
它能提供一个类编程环境,允许修改和重新组织文件中的数据,比sed高级些。。
来源于unix中的原始awk程序的GNU版本。。。gawk让流编辑器迈上了一个新的台阶,不再只是有命令处理,而是一种编程语言。。。。。
大量运用于生成报告,格式化日志文件。。
gawk options program file
options:
-F fs 指定行中分隔数据字段的字段分隔符
-f file 指定读取程序的文件名
-v var=value 定义 gawk程序中的一个变量及其默认值
-mf N 指定要处理中的文件中最大字段数
-mr N 指定数据文件中的最大数据行数
-W keyword 指定gawk的兼容模式或警告等级
----------
从命令行中使用gawk:
需要使用花括号{ 里面放命令 } ' 把{}包起来 '
当你: gawk '{print "hello oh"}'
print是gawk的内置命令
如果只是这样运行的话,gawk会一直等待从stdin的输入,直到你发出个信号说,流已经结束了:EOF:end-of-file
键盘按 Ctrl+d
[oh@localhost shell]$ gawk '{print "hello oh"}'
oh
hello oh
hi
hello oh
aaaaaa
hello oh
[oh@localhost shell]$
---
使用数据字段变量:
对于一个文本中的数据,gawk会自动给每行中的每个元素分配一个变量。默认情况下,变量会如下分配:
$0 代表整个文本行
$1 文本行中的第一个数据字段
$2 文本行中的第二个数据字段
$n 文本行中的第n个数据字段
而字段由字段分隔符来划分。。
也就是说,对gawk会依行处理文本中的数据,默认的字段分隔符是任意的空白字符(如空格或制表符)
[oh@localhost shell]$ cat tf
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$ gawk '{print $1}' tf
this
This
ond
this
this
[oh@localhost shell]$
[oh@localhost shell]$ cat tf
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$ gawk '{print $1}' tf
this
This
ond
this
this
[oh@localhost shell]$ gawk '{print $0}' tf
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$ gawk '{print $1}' tf
this
This
ond
this
this
[oh@localhost shell]$
可以看到输出了整个文件的第N个字段
gawk -F: '{print $1}' /etc/passed
指定了分隔符为: -F:
[oh@localhost shell]$ gawk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
。。。
nfsnobody
abrt
gdm
tomcat
webalizer
sshd
mysql
tcpdump
oprofile
oh
[oh@localhost shell]$
执行多条命令:
使用分号 或是>
[oh@localhost shell]$ echo "my name is oh" | gawk '{$4="hhh"; print $0}'
my name is hhh
[oh@localhost shell]$ gawk '{
> $4="ohhh"
> print $0}'
kkdfkds sjfksj sjfsklf fsfls//我输入的
kkdfkds sjfksj sjfsklf ohhh//它输出的
ksjfkljj jj jj jj//我输入的
ksjfkljj jj jj ohhh//它输出的
o o o o//我输入的
o o o ohhh//它输出的
[oh@localhost shell]$
-------
将命令写在文件中:
cat asd:
{
test="oh oh "
print $1 test $6
}
无需使用$符号,, 一个花括号里有好多的命令,不用; 另起一行就行。。。
-------
在处理数据前运行脚本:
gawk 'BEGIN {print "hello world"}'
有时可能需要在处理数据前运行脚本,比如为报告创建开头的部分。。。BEGIN关键字就有这个功能。。
他会强制gawk在读取数据前执行BEGIN关键字后指定的程序脚本:
[oh@localhost shell]$ gawk 'BEGIN {print "hello world"}'
hello world
[oh@localhost shell]$
显示了hello world后会快速退出而不用等待任何数据的输入。。BEGIN关键字的那行gawk命令只用来显示文本,
要处理数据的脚本得在其它地方写过。。。
[oh@localhost shell]$ cat tf
this is the first line
This is a test
ond line
this is the third line
this is the end line
[oh@localhost shell]$
gawk 'BEGIN {print "the data4 file contents: "} {print $1}' tf
再用个{}写 但是写在‘’内
gawk 'BEGIN {print "the data4 file contents: "} {print $1}' tf
[oh@localhost shell]$ gawk 'BEGIN {print "the data4 file contents: "} {print $1}' tf
the data4 file contents:
this
This
ond
this
this
[oh@localhost shell]$
---------
既然有里BEGIN 那么自然也有END 关键字了。。。。
END用于处理数据后再运行
[oh@localhost shell]$ gawk 'BEGIN {print "the data4 file contents: "} {print $1} END {print "end of file"}' tf
the data4 file contents:
this
This
ond
this
this
end of file
[oh@localhost shell]$
一个小小的例子
[oh@localhost shell]$ gawk -f script1 /etc/passwd
the latest list of users and shells
userid 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
dbus /sbin/nologin
usbmuxd /sbin/nologin
rpc /sbin/nologin
rtkit /sbin/nologin
avahi-autoipd /sbin/nologin
vcsa /sbin/nologin
apache /sbin/nologin
haldaemon /sbin/nologin
ntp /sbin/nologin
saslauth /sbin/nologin
postfix /sbin/nologin
pulse /sbin/nologin
rpcuser /sbin/nologin
nfsnobody /sbin/nologin
abrt /sbin/nologin
gdm /sbin/nologin
tomcat /sbin/nologin
webalizer /sbin/nologin
sshd /sbin/nologin
mysql /bin/bash
tcpdump /sbin/nologin
oprofile /sbin/nologin
oh /bin/bash
this concludes the listing
[oh@localhost shell]$ cat script1
BEGIN {
print "the latest list of users and shells"
print "userid shell"
print "----- -----"
FS=":"
}
{
print $1 " "$7
}
END {
print "this concludes the listing"
}
[oh@localhost shell]$
在script里赋值一个叫FS变量 这是定义字段分隔符的另一种方法。。。
可以看出,BEGIN 只在文本处理前执行一次。。。
END 只在文本执行后处理一次
中间的命令对每行都执行一次。。。
回到sed编辑器:
关于替换命令:s 就是substitute命令的简写。。但这也太简了吧。。。。。
1.替换标记:
默认情况下只能替换匹配到的第一个字符串。。
[oh@localhost shell]$ echo "aa aa"|sed 's/aa/bb/'
bb aa
[oh@localhost shell]$
要都替换掉的话,得使用替换标记(substitution flag)
s/pattern/replacement/flags
flag有四种:
数字:第几处匹配的内容给替换掉。。
g:所有匹配到的内容
w file :将替换的结果写到文件中。。。
[oh@localhost shell]$ echo "aa aa"|sed 's/aa/bb/'
bb aa
[oh@localhost shell]$ echo "aa aa"|sed 's/aa/bb/2'
aa bb
[oh@localhost shell]$ echo "aa aa"|sed 's/aa/bb/2 1'
sed: -e expression #1, char 11: multiple number options to `s' command
[oh@localhost shell]$ echo "aa aa"|sed 's/aa/bb/2,1'
sed: -e expression #1, char 10: unknown option to `s'
[oh@localhost shell]$ echo "aa aa"|sed 's/aa/bb/2;1'
sed: -e expression #1, char 11: missing command
[oh@localhost shell]$
[oh@localhost shell]$ echo "aa aa"|sed 's/aa/bb/g'
bb bb
只输出被替换过的行使用 p 加上sed的 -n选项 ;; -n会禁止sed编辑器输出。。但p 会输出修改过的行。。。这一来,就可以只输出被substitute命令修改过的行了
正常来说,sed的输出是在stdout里的。。。当你使用 w file 时,只有包含匹配模式的行才会保存到指定的输出文件file里。。
2.
替换一些尴尬的字符:
当你想替换正斜线时,可能会遇到一些问题,比较麻烦。。。
得使用\
sed 's/\/etc/\/opt/' /etc/passwd
可读性差。。。。
所以,使用!来替代原有的/ 以!作为字符串分隔符。
sed 's!/etc!/opt!' /etc/passwd
-------------
使用地址。。。
行寻址(line addressing) 当你没想匹配所有的行,而只是某些特定的行时。。
寻址的方式有两种:
1.行的数字范围。。
2.用文本模式来过滤输出的行。。。
两种方式都是以下的命令方式:
[address] command
或者:
address {
command1
command2
command3
}