《linux命令行与shell脚本编程大全》第三版 - 核心笔记(3/4):sed和gawk

时间:2021-11-30 14:28:23
《linux命令行与shell脚本编程大全》
全书4部分:
☆ 【1】linux命令行(1-10章)
☆ 【2】shell脚本编程基础(11-16章)
☆ 【3】高级shell脚本编程(17-23章):sed编辑器和gawk程序
☆ 【4】创建实用的脚本(24-26章)


>>第19章丶sed编辑器和gawk程序

sed编辑器
流编辑器,和普通的交互式文本编辑器恰好相反。sed编辑器会执行以下操作:
(1) 一次从输入中读取一行数据。
(2) 根据所提供的编辑器命令匹配数据。
(3) 按照命令修改流中的数据。
(4) 将新的数据输出到STDOUT。


sed命令的格式如下。
    sed options script file
sed命令选项:
-e script 在处理输入时,将script中指定的命令添加到已有的命令中
-f file 在处理输入时,将file中指定的命令添加到已有的命令中
-n 不产生命令输出,使用print命令来完成输出
默认情况下, sed编辑器会将指定的命令应用到STDIN输入流上。这样你可以直接将数据通过管道输入sed编辑器处理。

$: echo "This is a test." | sed 's/test/big test/'
This is a big 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编辑器 并不会修改文本文件的数据。它只会将修改后的数据发送到STDOUT。

-e选项

在命令行使用多个编辑器命令。
$: 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.
// 要在封尾单引号所在行结束命令。 bash shell一旦发现了封尾的单引号,就会执行命令。s命令的结尾符号/必须要有,否则报错。

-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.

[ 窍门]我们很容易就会把sed编辑器脚本文件与bash shell脚本文件搞混。为了避免这种情况,可以使用 .sed作为sed脚本文件的扩展名。

gawk程序

提供一个类编程环境来修改和重新组织文件中的数据。
$: sudo apt-get install gawk
$: gawk -W version
GNU Awk 3.1.8
版权所有 © 1989, 1991-2010 *软件基金会(FSF)。

gawk程序会执行以下操作:
 定义变量来保存数据;
 使用算术和字符串操作符来处理数据;
 使用结构化编程概念(比如if-then语句和循环)来为数据处理增加处理逻辑;
 通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。

gawk程序的报告生成能力通常用来从大文本文件中提取数据元素,并将它们格式化成可读的报告。其中最完美的例子是【 格式化日志文件】。

gawk程序的基本格式如下:
    gawk options program file

gawk程序选项:
-F fs           指定行中划分数据字段的字段分隔符,如-F:即以冒号来划分
-f file         从指定的文件中读取程序
-v var=value    定义gawk程序中的一个变量及其默认值
-mf N           指定要处理的数据文件中的最大字段数
-mr N           指定数据文件中的最大数据行数
-W keyword      指定gawk的兼容模式或警告等级

从命令行读取程序脚本:
Ctrl+D组合键会在bash中产生一个EOF字符。
$: gawk '{printf "Hello World!"}'
This is a test.
Hello World!
Hello World!hello
Hello World!
Hello World!^D
// Ctrl+D组合键会在bash中产生一个EOF字符。能够终止gawk程序并返回到命令行。

使用数据字段变量:
默认情况下, gawk会将如下变量分配给它在文本行中发现的数据字段:
 $0代表整个文本行;
 $1代表文本行中的第1个数据字段;
 $2代表文本行中的第2个数据字段;
 $n代表文本行中的第n个数据字段。

每个数据字段都是通过字段分隔符划分的。gawk中默认的字段分隔符是任意的空白字符(例如空格或制表符)。
$: cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.
$: gawk '{print $2}' data2.txt
line
lines
lines

-F:
$: gawk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
...

$: echo "My name is Rich" | gawk '{$4="Christine"; print $0}'
My name is Christine

$: 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
[...]

有时可能需要在处理数据前运行脚本,比如为报告创建标题。BEGIN关键字就是用来做这个的。它会强制gawk在读取数据前执行BEGIN关键字后指定的程序脚本。
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

$: cat script4.gawk
BEGIN {
    print "The latest list of users and shells"
    print " UserID \t Shell"
    print "-------- \t -------"
    FS=":"
}
{
    print $1 " \t " $7
}
END {
    print "This concludes the listing"
}


$: gawk -f script4.gawk /etc/passwd
The latest list of users and shells
UserID Shell
-------- -------
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
...
Christine /bin/bash
mysql /bin/bash
Samantha /bin/bash
Timothy /bin/bash
This concludes the listing

sed编辑器标记命令

s替换标记

要让替换命令能够替换一行中不同地方出现的文本必须使用替换标记(substitution flag)。替换标记会在替换命令字符串之后设置。
    s/pattern/replacement/flags
有4种可用的替换标记:
 数字,表明新文本将替换第几处模式匹配的地方;
 g,表明新文本将会替换所有匹配的文本;
 p,表明原先行的内容要打印出来;
 w file,将替换的结果写到文件中。


$ sed 's/test/trial/2' data4.txt
// 将data4.txt文件中的第二处出现test的地方替换为trial
$ sed 's/test/trial/g' data4.txt
// 将data4.txt中所有出现test的地方替换为trial
$ sed -n 's/test/trial/p' data5.txt
// -n与p一般配合使用,只输出test被trial替换后,即修改过的行。
$ sed 's/test/trial/w test.txt' data5.txt
// 将data5.txt中的test替换为trial后,输出到屏幕并保存到文件test.txt中

sed编辑器允许选择其他字符来作为替换命令中的字符串分隔符,而不必一定要使用转义字符'\':
$ sed 's!/bin/bash!/bin/csh!' /etc/passwd

如果只想将命令作用于特定行或某些行,则必须用行寻址(line addressing)。
在sed编辑器中有两种形式的行寻址:
 以数字形式表示行区间
 用文本模式来过滤出行

两种形式都使用相同的格式来指定地址:
    [address]command
也可以将特定地址的多个命令分组:
address {
    command1
    command2
    command3
}


$ sed '2s/dog/cat/' data1.txt
// 只修改地址指定的第二行的文本:2
$ sed '2,3s/dog/cat/' data1.txt
// 只修改地址指定的第二行和第三行的文本:2,3
$ sed '2,$s/dog/cat/' data1.txt
// 修改地址指定的第二行开始的所有行文本:2,$

也可以在多行实现,需要加{}:
$ sed '2{
> s/fox/elephant/
> s/dog/cat/
> }' data1.txt

The quick brown fox jumps over the lazy dog.
The quick brown elephant jumps over the lazy cat.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.

sed编辑器允许指定文本模式来过滤出命令要作用的行。格式如下:
    /pattern/command
必须用正斜线将要指定的pattern封起来。
$: grep jiangyuan /etc/passwd
jiangyuan:x:1001:1001:jiangyuan,,,:/home/jiangyuan:/bin/bash
$: sed '/jiangyuan/s/bash/csh/' /etc/passwd > passwd.bak && grep jiangyuan passwd.bak
jiangyuan:x:1001:1001:jiangyuan,,,:/home/jiangyuan:/bin/csh
// 过滤jiangyuan的行,sed过滤后的结果输出到passwd.bak文件,搜passwd.bak文件中搜索出包含jiangyuan的行。

d删除行

sed编辑器不会修改原始文件。你删除的行只是从sed编辑器的输出中消失了。原始文件仍然包含那些“删掉的”行。
$ sed '3d' data6.txt
// 在输出流中删除第三行
$ sed '2,3d' data6.txt
// 在输出流中删除第二、三行
$ sed '3,$d' data6.txt
// 在输出流中删除第三行开始的所有行
$ sed '/number 1/d' data6.txt
// 在输出流中删除匹配到了 number 1 的行

i前插行a后插行

sed编辑器允许向数据流插入和附加文本行。
 插入(insert)命令(i)会在指定行前增加一个新行;
 附加(append)命令(a)会在指定行后增加一个新行。

格式如下:
sed '[address]command\
new line'


$ echo "Test Line 2" | sed 'i\Test Line 1'
// 在行2前插入行1
$ echo "Test Line 2" | sed 'a\Test Line 1'
// 在行2后插入行1
$ echo "Test Line 2" | sed 'i\
> Test Line 1'

// 在行2前插入行1
$ sed '3i\
> This is an inserted line.' data6.txt

// 在文件中的第3行前插入一行内容
$ sed '3a\
> This is an appended line.' data6.txt

// 在文件中的第3行后插入一行内容
$ sed '$a\
> This is a new line of text.' data6.txt

// 在文件中的最后一行后前插入一行内容
$ sed '1i\
> This is one line of new text.\
> This is another line of new text.' data6.txt

// 在文件中的第1行前插入两行内容

c修改行

 修改(change)命令( c)会把指定行修改为一个新行。
$ sed '3c\
> This is a changed line of text.' data6.txt

// 修改第三行的内容
$ sed '/number 3/c\
> This is a changed line of text.' data6.txt

// 修改匹配到number 3的行内容
$ sed '2,3c\
> This is a new line of text.' data6.txt

// 修改2和3行为一行内容

y转换行

转换(transform)命令(y)是唯一可以处理单个字符的sed编辑器命令。转换命令格式如下:
    [address]y/inchars/outchars/
转换命令会对inchars和outchars值进行一对一的映射。 inchars中的第一个字符会被转换为outchars中的第一个字符,第二个字符会被转换成outchars中的第二个字符。这个映射过程会一直持续到处理完指定字符。
$ sed 'y/123/789/' data8.txt
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4.
This is line number 7 again.
This is yet another line.
This is the last line in the file.

sed的打印

另外有3个命令也能用来打印数据流中的信息:
 p命令用来打印文本行;
 等号(=)命令用来打印行号;
 l(小写的L)命令用来列出行。


$ echo "this is a test" | sed 'p'
this is a test
this is a test
$ sed -n '/number 3/p' data6.txt
This is line number 3.
$ sed -n '2,3p' data6.txt
This is line number 2.
This is line number 3.
$ sed '=' data1.txt
1
The quick brown fox jumps over the lazy dog.
$ sed -n 'l' data9.txt
This\tline\tcontains\ttabs.

sed 处理文件

写入文件, w命令用来向文件写入行。该命令的格式如下:
    [address]w filename
将数据流中的前两行打印到一个文本文件中。
$ sed '1,2w test.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
$ cat test.txt
This is line number 1.
This is line number 2.
// 如果你不想让行显示到STDOUT上,你可以用sed命令的-n选项。

从文件读取数据,读取(read)命令( r)允许你将一个独立文件中的数据插入到数据流中。读取命令的格式如下:
    [address]r filename

$ cat data12.txt
This is an added line.
This is the second added line.
$ sed '3r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an added line.
This is the second added line.
This is line number 4.






2017.07.02
第19章完... (全书未完待续!)