《Linux命令行与shell脚本编程大全》初识sed和gawk
文本处理
sed编辑器
sed编辑器可以基于输入到命令行的或是存储在命令文本文件中的命令来处理数据流中的数据。
它每次读取一行,用提供的编辑器命令匹配数据、按命令中指定的方式修改流中的数据,然后将生成的数据输出到STDOUT。在流编辑器将所有命令与一行数据进行匹配后,它会读取下一行数据并重复这个过程。在流编辑器处理完流中的所有数据行后,它就会终止。
sed命令格式:
sed options script file
sed命令选项
选项 描述
-e script 在处理输入时,将script中指定的命令添加到运行的命令中
-f file 在处理输入时,将file中指定的命令添加到运行的命令中
-n 不要为每个命令生成输出,等待print命令来输出
在命令行定义编辑器命令
默认情况下,sed会编辑器会将指定的命令应用到STDIN输入流上。
[plain]
$ echo "This is a test" | sed 's/a/not a/'
This is not a test
在命令行使用多个编辑器命令
使用-e即可。
注意:多个命令都写在同一对引号之间,并用分号隔开。并且在命令末尾和分号之间不能有空格。
[plain]
$ echo "This is a test" | sed -e 's/a/not a/;s/This/That/'
That is not a test
从文件中读取编辑器命令
[plain]
$ cat sed_script
s/brown/white/
s/fox/elephant/
使用-f选项即可。
[plain]
$ echo "The quick brown fox jumps over the lazy dog." | sed -f sed_script
The quick white elephant jumps over the lazy dog.
文件中的sed命令可以使用换行或分号隔开
gawk程序
在gawk编程语言中,可以做下面的事:
1.定义变量来保存数据
2.使用算数和字符串操作符来处理数据
3.使用结构化编程概念,比如if-then语句和循环
4.提取数据文件中的数据元素并将他们按另一顺序或格式重新放置。
gawk命令格式:
gawk option program file
gawk选项
选项 描述
-F fs 指定行中分隔数据字段的字段分隔符
-f file 指定读取程序的文件名
-v var=value 定义gawk程序中的一个变量以及默认值
-mf N 指定要处理的数据文件中的最大字段数
-mr N 指定数据文件中的最大数据行数
-W keyword 指定gawk的兼容模式或警告等级
从命令行读取程序脚本
gawk程序用一对花括号来定义。
由于gawk命令行假定脚本是单个文本字符串,所以必须将脚本放到单引号中。
[plain]
$ gawk '{print "Hello"}'
键入回车之后,并不会马上执行,等待你输入文本。gawk会对这行文本运行一遍所有的程序脚本
和sed一样,gawk程序会针对数据流中的每行文本执行一遍程序脚本。
使用数据字段变量
gawk会将如下变量分配给它在文本行中发现的每个数据字段:
$0表示整个文本行;$1表示文本行中第一个数据字段,依此类推
gawk中默认的字段分隔符是任意空白字符
[plain]
$ echo "A B C
> D E F" | gawk '{print $1}'
A
D
使用-F选项指定分隔符
[plain]
$ gawk -F : '{print $1}' /etc/passwd
root
daemon
bin
sys
……
在程序脚本中使用多个命令
同sed,多个命令使用分号隔开即可。
[plain]
$ echo "I'm a person." | gawk '{$3="man.";print $0}'
I'm a man.
这里先将$3赋值,然后打印这句话。打印得结果是已经替换了$3之后的结果了。
从文件中读取程序
[plain]
$ cat gawk_test
{
text="'s home directory is "
print $1 text $6
}
同样可以使用多个命令,可以用换行或分号分割命令
[plain]
$ gawk -F: -f gawk_test /etc/passwd
root's home directory is /root
daemon's home directory is /usr/sbin
……
gawk在引用变量得时候,并不像shell那样,需要使用美元符
在处理数据前运行脚本
BEGIN关键字会在处理数据前,执行指定的脚本
[plain]
$ gawk 'BEGIN { print "hello world"}'
hello world
在处理数据后运行脚本
当然是使用END关键字了
[plain]
$ cat gawk_test
BEGIN {
print "Before read the file"
FS=":"
}
{
print $1
}
END {
print "The End"
}
注意:使用FS设置分割符
[plain]
$ gawk -f gawk_test /etc/passwd
Before read the file
root
daemon
……
sshd
Debian-exim
The End
sed编辑器基础
更多的替换选项
替换标记
默认情况下,对匹配到的内容只会替换一次
[plain]
$ echo "That is a test." | sed 's/ //'
Thatis a test.
如果想改变这种方式,需要使用替换标记
s/pattern/replacement/flags
有4种替换标记:
数字,表明将替换第几处模式匹配的地方
[plain]
$ echo "That is a test." | sed 's/ //2'
That isa test.
$ echo "That is a test." | sed 's/ //6'
That is a test.
g,替换所有匹配到的文本
[plain]
$ echo "That is a test." | sed 's/ //g'
Thatisatest.
p,表明原来行的地方要打印出来。通常与-n选项一起使用
上面已经说过,-n选项表示不输出,等待print命令来输出。
[plain]
$ echo "That is a test." | sed -n 's/ //p'
Thatis a test.
w file,将替换的结果写到文件中
[plain]
$ echo "That is a test." | sed -n 's/ //w out'
$ cat out
Thatis a test.
替换字符
如果我们想要替换文本中出现的文件路径,那么就需要转义符
[plain]
$ pwd | sed 's///home///myhome/'
/myhome/su1216/android/source/linux_learned
或者,我们也可以把命令中的字符串分割符“/”给替换掉
[plain]
$ pwd | sed 's@home@myhome@'
/myhome/suzhaoqiang/android/source/linux_learned
使用地址
默认情况下,sed会对所有行使用命令,如果只想将命令作用于特定某些行,需要使用行寻址(line addressing)
sed中有两种形式的行寻址:
1.行的数字范围
2.用文本模式来过滤出某行
两种形式都使用相同的格式来指定地址:
[address] command
也可以为特定地址将多个命令放在一起:
address {
command1
command2
command3
}
数字方式的行寻址
[plain]
$ cat test.txt
This is a test.
This is a test.
This is a test.
This is a test.
This is a test.
This is a test.
This is a test.
$ sed '3,$s/This/That/' test.txt
This is a test.
This is a test.
That is a test.
That is a test.
That is a test.
That is a test.
That is a test.
从第三行开始,到最后一行(最后一行用美元符号表示)进行替换
使用文本模式过滤器
格式如下:
/pattern/command
该命令只会作用到匹配文本模式的行上。sed在文本模式中采用正则表达式。
[plain]
sed '/su1216/s!home!myhome!' /etc/passwd
root:x:0:0:root:/root:/bin/bash
……
su1216:x:1000:1000:su1216,,,:/myhome/su1216:/bin/bash
……
组合命令
需要对单行执行多条命令的话,可以使用花括号将多条命令组合在一起
[plain]
$ sed '2{
s/This/That/
s/test/good test/
}' test.txt
This is a test.
That is a good test.
This is a test.
This is a test.
删除行(delete)
删除行的命令为d,如果不指定行号,那么就全部删除。
[plain]
$ sed '2,4d' test.txt
line 1
line 5
line 6
sed编辑器的模式匹配也适用于删除命令:
[plain]
$ sed '/line 3/d' test.txt
line 1
line 2
line 4
line 5
line 6
注意:sed不会修改原始文件。
可以用两个文本模式来删除某个范围内得行。
指定的第一个文本模式会打开行删除功能,第二个会关闭行删除功能。如果没有匹配到第二个,那么后面的文本将全部删除。
如果匹配到了第二个,那么sed还会继续尝试匹配第一个,继续尝试再次打开删除功能!
[plain]
$ sed '/line 2/,/line 4/d' test.txt
line 1
line 5
line 6
插入和附加文本
插入(insert)命令i会在指定行前加一个新行
追加(append)命令a会在指定行后加一个新行
格式如下:
sed '[address]command/
new line'
[plain]
$ echo "Line" | sed 'i/Line 1'
Line 1
Line
$ echo "Line" | sed 'a/Line 1'
Line
Line 1
在数据流的最后添加新行
[plain]
$ sed '$a/new line' test.txt
line 1
line 2
line 3
line 4
line 5
line 6
new line
修改行(change)
和之前的使用完全一样
使用地址区间的时候需要注意,sed会把区间中的所有内容作为一个整体用新行替换
[plain]
$ sed '2,4c/new line' test.txt
line 1
new line
line 5
line 6
转换命令
转换(transform,y)命令是唯一可用处理单个字符的sed编辑器命令
格式如下:
[addressly/inchars/outchars/
转换命令会对inchars和outchars按顺序做一个一一映射。
如果inchars和outchars长度不同,sed则会产生错误信息
[plain]
$ sed 'y/123/abc/' test.txt
A:aabbaacc
B:44aa55bb
转换命令是全局的,他们将所有指定的字符都替换成目标字符。
回顾打印
用来打印数据流中的信息的命令:
1.p,用来打印文本行
2.等号(=)命令,用来打印行号
3.l(小写L)命令,用来列出行
打印行
和替换命令中的p标记类似,p命令可以打印sed编辑器输出中的一行
[plain]
$ echo "hello" | sed 'p'
hello
hello
$ echo "hello" | sed -n 'p'
hello
也可以使用文本模式
[plain]
$ cat test.txt
A:11221133
B:44115522
line 3
line 4
line 5
$ sed -n '/line/p' test.txt
line 3
line 4
line 5
可以与替换命令一起使用,下面是修改一行,并且打印出修改前的这一行
[plain]
$ sed -n '/3/{p;s/line/Line/p}' test.txt
A:11221133
line 3
Line 3
含有3的有两行,其中后面一行满足条件,然后被替换。
打印行号
[plain]
$ sed '=' test.txt
1
A:11221133
2
B:44115522
3
line 3
4
line 4
5
line 5
行号由换行符决定。
[plain]
$ sed -n '/line/{=;p}' test.txt
3
line 3
4
line 4
5
line 5
列出行
此命令允许打印数据流中的文本和不可打印的ASCII字符。
任何不可打印字符都用他们的八进制值前加一个反斜线或标准C风格的命名法。
[plain]
$ sed -n 'l' test.txt
A:11221133$
B:44115522$
line 3$
line 4$
line 5$
比如制表符用/t表示,行结束用$表示。
用sed和文件一起工作
向文件写入
格式如下:
[address]w filename
[plain]
$ sed '1,2w sed_w_test' test.txt
A:11221133
B:44115522
line 3
line 4
line 5
$ cat sed_w_test
A:11221133
B:44115522
当然,我们可以改成下面的形式
[plain]
$ sed -n '1,2w sed_w_test' test.txt
$ cat sed_w_test
A:11221133
B:44115522
从文件读取数据
格式如下:
[address]r filename
读取命令允许将一个独立文件中的数据插入到数据流中。
[plain]
$ cat sed_w_test
A:11221133
B:44115522
$ sed '4r sed_w_test' test.txt
A:11221133
B:44115522
line 3
line 4
A:11221133
B:44115522
line 5
如果想插到文件末尾,可以使用$