Linux系统提供了两个常见的具备上述功能的工具。本节将会介绍Linux世界中最广泛使用的 两个命令行编辑器:sed和gawk。
1. sed编辑器
sed
编辑器被称作流编辑器(stream editor)
,流编辑器则会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。
sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储 在一个命令文本文件中。sed编辑器会执行下列操作。
(1) 一次从输入中读取一行数据。
(2) 根据所提供的编辑器命令匹配数据。
(3) 按照命令修改流中的数据。
(4) 将新的数据输出到STDOUT。
sed命令的格式如下。
sed options script file
选项允许你修改sed命令的行为,可以使用的选项已在表19-1
中列出。
script参数指定了应用于流数据上的单个命令
。如果需要用多个命令
,要么使用-e选项
在命令行中指定,要么使用-f选项
在单独的文件中指定。
1.1 在命令行定义编辑器命令
默认情况下,sed编辑器会将指定的命令应用到STDIN输入流上。这样你可以直接将数据通 过管道输入sed编辑器处理。这里有个简单的示例。
$ echo "This is a test" | sed 's/test/big test/'
This is a big test
$
这个例子在sed编辑器中使用了s命令。s命令
会用斜线间指定的第二个文本字符串来替换
第 一个文本字符串模式。在本例中是big test替换了test。
当然,这个简单的测试只是修改了一行数据。不过就算编辑整个文件,处理速度也相差无几。
$ cat data1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$
$ sed 's/dog/cat/' data1.txt
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
$
重要的是,要记住,sed编辑器并不会修改文本文件的数据
。它只会将修改后的数据发送到 3 STDOUT。如果你查看原来的文本文件,它仍然保留着原始数据。
1.2 在命令行使用多个编辑器命令
要在sed命令行上执行多个命令时,只要用-e选项
就可以了。
$ sed -e 's/brown/green/; s/dog/cat/' data1.txt
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
$
两个命令都作用到文件中的每行数据上。命令之间必须用分号
隔开,并且在命令末尾和分号 8 之间不能有空格。
如果不想用分号,也可以用bash shell中的次提示符来分隔命令。
$sed -e '
> s/brown/green/
> s/fox/elephant/
> s/dog/cat/' data1.txt
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
$
1.3 从文件中读取编辑器命令
可以在sed命令中用-f选项
来指定文件。
$ cat script1.sed
s/brown/green/
s/fox/elephant/
s/dog/cat/
$
$ sed -f script1.sed data1.txt
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
$
1.4 更多的替换选项
1.4.1 s命令:替换
替换命令在替换多行中的文本时能正常工作,但默认情况下它只替换每行中出现的第一处
。
$ cat data4.txt
This is a test of the test script.
This is the second test of the test script.
$
$ sed 's/test/trial/' data4.txt
This is a trial of the test script.
This is the second trial of the test script.
$
要让替换命令能够替换一行中不同地方出现的文本必须使用替换标记(substitution flag)
。替换标 记会在替换命令字符串之后设置。
s/pattern/replacement/flags
有4种可用的替换标记:
数字
,表明新文本将替换第几处模式匹配的地方;g
,表明新文本将会替换所有匹配的文本;p
,表明原先行的内容要打印出来;w file
,将替换的结果写到文件中。
数字替换标记
中,可以指定sed编辑器用新文本替换第几处模式匹配的地方。
$ sed 's/test/trial/2' data4.txt
This is a test of the trial script.
This is the second test of the trial script.
$
g替换标记
使你能替换文本中匹配模式所匹配的每处地方。
$ sed 's/test/trial/g' data4.txt
This is a trial of the trial script.
This is the second trial of the trial script. $
p替换标记
会打印与替换命令中指定的模式匹配的行。这通常会和sed的-n选项一起使用。
-n选项将禁止sed编辑器输出。但p替换标记会输出修改过的行。将二者配合使用的效果就是 只输出被替换命令修改过的行。
$ cat data5.txt
This is a test line.
This is a different line.
$
$ sed -n 's/test/trial/p' data5.txt This is a trial line.
$
w替换标记
会产生同样的输出,不过会将输出保存到指定文件中。
$ sed 's/test/trial/w test.txt' data5.txt This is a trial line.
This is a different line.
$
$ cat test.txt
This is a trial line.
$
sed编辑器的正常输出是在STDOUT中,而只有那些包含匹配模式的行才会保存在指定的输出 文件中。
直接替换原文件内容
sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
这条命令使用了sed(stream editor)工具来直接(-i选项)修改/etc/apt/sources.list文件,命令的具体作用是将文件中所有出现的archive.ubuntu.com字符串替换为mirrors.aliyun.com。
-i选项
告诉sed直接修改文件内容,而不是将结果输出到标准输出(通常是屏幕)。如果没有-i选项,sed的修改结果只会显示在屏幕上,原文件不会被改变。
1.4.2 使用地址
默认情况下,在sed编辑器中使用的命令会作用于文本数据的所有行。如果只想将命令作用 于特定行或某些行,则必须用行寻址(line addressing)
。
在sed编辑器中有两种形式
的行寻址:
- 以数字形式表示行区间
- 用文本模式来过滤出行
数字方式的行寻址
在命令中指定的地址可以是单个行号
,或是用起始行号、逗号以及结尾行号
指定的一定区间范围内的行。这里有个sed命令作用到指定行号的例子。
sed编辑器只修改地址指定的第二行的文本。
$ sed '2s/dog/cat/' data1.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
$
另一个例子,这次使用了行地址区间
$ sed '2,3s/dog/cat/' data1.txt
The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy dog $
如果想将命令作用到文本中从某行开始的所有行,可以用特殊地址——美元符。
$ sed '2,$s/dog/cat/' data1.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
$
使用文本模式过滤器
sed编辑器允许指定文本模式来过 滤出命令要作用的行。格式如下:
/pattern/command
必须用正斜线将要指定的pattern封起来。sed编辑器会将该命令作用到包含指定文本模式的行上。
举个例子,如果你想只修改用户Samantha的默认shell,可以使用sed命令。
$ grep Samantha /etc/passwd
Samantha:x:502:502::/home/Samantha:/bin/bash
$
$ sed '/Samantha/s/bash/csh/' /etc/passwd
Samantha:x:502:502::/home/Samantha:/bin/csh
$
1.4.3 d命令:删除行
删除命令d
名副其实,它会删除匹配指定寻址模式的所有行。使用该命令时要特别小心,如 果你忘记加入寻址模式的话,流中的所有文本行都会被删除。
$ cat data1.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
$
$ sed 'd' data1.txt
$
指定行号
$ cat data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
$
$ sed '3d' data6.txt
This is line number 1.
This is line number 2.
This is line number 4.
$
指定区间
$ sed '2,3d' data6.txt
This is line number 1.
This is line number 4.
$
通过特殊的文件结尾字符
$ sed '3,$d' data6.txt
This is line number 1.
This is line number 2.
$
sed编辑器的模式匹配特性也适用于删除命令。sed编辑器会删掉包含匹配指定模式的行。
$ sed '/number 1/d' data6.txt
This is line number 2.
This is line number 3.
This is line number 4.
$
2. gawk程序
gawk程序能提供一个类编程环境
来修改和重新组织文件中的数据。
在gawk编程语言中,你可以做下面的事情:
- 定义变量来保存数据;
- 使用算术和字符串操作符来处理数据;
- 使用结构化编程概念(比如if-then语句和循环)来为数据处理增加处理逻辑;
- 通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。
gawk程序的基本格式如下:
gawk options program file
表19-2
显示了gawk程序的可用选项。
gawk的强大之处在于程序脚本
。可以写脚本来读取文本行的数据,然后处理并显示数据,创建任何类型的输出报告。
2.1 从命令行读取程序脚本
由于gawk命令行假定脚本是单个文本字符串,你还必须将脚本放到单引号
中
$ gawk '{print "Hello World!"}'
This is a test
Hello World!
hello
Hello World!
这个程序脚本定义了一个命令print命令
。这个命令名副其实:它会将文本打印到STDOUT
。
如果尝试运行这个命令,你可能会有些失望,因为什么都不会发生。原因在于没有在命令行上指 定文件名,所以gawk程序会从STDIN接收数据。在运行这个程序时,它会一直等待从STDIN输入 的文本。
如果你输入一行文本并按下回车键,gawk会对这行文本运行一遍程序脚本。
2.2 使用数据字段变量
默认情况下,gawk会将如下变量分配给它在文本行中发现的数据字段:
$0代表整个文本行;
$1代表文本行中的第1个数据字段;
$2代表文本行中的第2个数据字段;
$n代表文本行中的第n个数据字段。
在下面的例子中,gawk程序读取文本文件,只显示第1个数据字段的值。
$ cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.
$
$ gawk '{print $1}' data2.txt One
Two
Three
$
该程序用$1
字段变量来仅显示每行文本的第1个数据字段。
2.3 在程序脚本中使用多个命令
要在命令行上的程序脚本中使用多条命令,只要在命令之间放个分号
即可。
$ echo "My name is Rich" | gawk '{$4="Christine"; print $0}'
My name is Christine
$
也可以用次提示符一次一行地输入程序脚本命令。
$ gawk '{
> $4="Christine"
> print $0}'
My name is Rich
My name is Christine
$
2.4 从文件中读取程序
$ cat script2.gawk
{print $1 "'s home directory is " $6}
$
$ gawk -F: -f script2.gawk /etc/passwd
root's home directory is /root
bin's home directory is /bin
daemon's home directory is /sbin
adm's home directory is /var/adm
lp's home directory is /var/spool/lpd
[...]
Christine's home directory is /home/Christine Samantha's home directory is /home/Samantha Timothy's home directory is /home/Timothy
$
2.5 在处理数据前运行脚本
有时可能需要在处理数据前运行脚本,比如为报告创建标题。BEGIN关键字
就是用来做这个的。它会强制gawk在读取数据前执行BEGIN关键字后指定的程序脚本
。
$ cat data3.txt
Line 1
Line 2
Line 3
$
$ gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}' data3.txt
The data3 File Contents:
Line 1
Line 2
Line 3
2.6 在处理数据后运行脚本
END关键字
允许你指定一个程序脚本,gawk会在读完数据后执行它。
$ gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}
> END {print "End of File"}' data3.txt
The data3 File Contents:
Line 1
Line 2
Line 3
End of File
$