概述
01. sed 编辑器
sed编辑器被称作流编辑器,和普通的交互式文本编辑器恰好相反。在交互式文本编辑器中(比如vim),你可以用键盘命令来交互式地插入、删除或替换数据中的文本。流编辑器则会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。
sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本文件中。sed编辑器的处理过程如下。
- 一次从输入中读取一行数据。
- 根据所提供的编辑器命令匹配数据。
- 按照命令修改流中的数据。
- 将新的数据输出到STDOUT。
在流编辑器将所有命令与一行数据匹配完毕后,它会读取下一行数据并重复这个过程。在流编辑器处理完流中的所有数据行后,它就会终止。由于命令是按顺序逐行给出的,sed编辑器只需对数据流进行一遍处理就可以完成编辑操作。这使得sed编辑器要比交互式编辑器快得多,你可以快速完成对数据的自动修改。
选 项 描 述
-n 使用安静模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则禁止sed编辑器输出。
-e 直接在命令列模式上进行 sed 的动作编辑。
-f 直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作。
-r sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)。
-i 直接修改读取的文件内容,而不是输出到终端。
01. 在命令行定义编辑器命令
默认情况下,sed编辑器会将指定的命令应用到STDIN输入流上。这样你可以直接将数据通过管道输入sed编辑器处理。
# 替换字符串
[root@ufo130 ~]# echo "This is a test" | sed 's/test/big test/'
This is a big test
重要的是,要记住,sed编辑器并不会修改文本文件的数据。它只会将修改后的数据发送到STDOUT。如果你查看原来的文本文件,它仍然保留着原始数据。
02. 在命令行使用多个编辑器命令
要在sed命令行上执行多个命令时,只要用-e选项就可以了。
sed -e 's/brown/green/; s/dog/cat/' data1.txt
两个命令都作用到文件中的每行数据上。命令之间必须用分号隔开,并且在命令末尾和分号之间不能有空格。如果不想用分号,也可以用bash shell中的次提示符来分隔命令。
[root@ufo130 ~]# sed -e '
> s/brown/green/
> s/fox/elephant/
> s/dog/cat/' data1.txt
必须记住,要在封尾单引号所在行结束命令。
03. 从文件中读取编辑器命令
最后,如果有大量要处理的sed命令,那么将它们放进一个单独的文件中通常会更方便一些。可以在sed命令中用-f选项来指定文件,在这种情况下,不用在每条命令后面放一个分号。
[root@ufo130 ~]# cat script1.sed
s/brown/green/
s/fox/elephant/
s/dog/cat/
[root@ufo130 ~]# sed -f script1.sed data1.txt
02. gawk 程序
虽然sed编辑器是非常方便自动修改文本文件的工具,但其也有自身的限制。通常你需要一个用来处理文件中的数据的更高级工具,它能提供一个类编程环境来修改和重新组织文件中的数据。这正是gawk能够做到的。
gawk程序是Unix中的原始awk程序的GNU版本。gawk程序让流编辑迈上了一个新的台阶,它提供了一种编程语言而不只是编辑器命令。
- 定义变量来保存数据
- 使用算术和字符串操作符来处理数据
- 使用结构化编程概念(比如if-then语句和循环)来为数据处理增加处理逻辑
- 通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告
选 项 描 述
-F fs 指定行中划分数据字段的字段分隔符
-f file 从指定的文件中读取程序
-v var=value 定义gawk程序中的一个变量及其默认值
-mf N 指定要处理的数据文件中的最大字段数
-mr N 指定数据文件中的最大数据行数
-W keyword 指定gawk的兼容模式或警告等级
01. 从命令行读取程序脚本
gawk程序脚本用一对花括号来定义。你必须将脚本命令放到两个花括号 { } 中。由于gawk命令行假定脚本是单个文本字符串,你还必须将脚本放到单引号中。
gawk '{print "Hello World!"}'
如果尝试运行这个命令,你可能会有些失望,因为什么都不会发生。原因在于没有在命令行上指定文件名,所以gawk程序会从STDIN接收数据。在运行这个程序时,它会一直等待从STDIN输入的文本。
要终止这个gawk程序,你必须表明数据流已经结束了。Ctrl+D组合键会在bash中产生一个EOF字符。这个组合键能够终止该gawk程序并返回到命令行界面提示符下。
02. 使用数据字段变量
默认情况下, gawk会将如下变量分配给它在文本行中发现的数据字段:
- $0代表整个文本行;
- $1代表文本行中的第1个数据字段;
- $2代表文本行中的第2个数据字段;
- $n代表文本行中的第n个数据字段。
在文本行中,每个数据字段都是通过字段分隔符划分的。 gawk在读取一行文本时,会用预定义的字段分隔符划分每个数据字段。 gawk中默认的字段分隔符是任意的空白字符(例如空格或制表符)。
[root@ufo130 ~]# cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.
[root@ufo130 ~]# gawk '{print $1}' data2.txt
One
Two
Three
如果你要读取采用了其他字段分隔符的文件,可以用-F选项指定。
[root@ufo130 ~]# gawk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
03. 在程序脚本中使用多个命令
要在命令行上的程序脚本中使用多条命令,只要在命令之间放个分号即可。
[root@ufo130 ~]# echo "My name is Rich" | gawk '{$4="Christine"; print $0}'
My name is Christine
注意, gawk程序在输出中已经将原文本中的第四个数据字段替换成了新值。
也可以用次提示符一次一行地输入程序脚本命令。
[root@ufo130 ~]# gawk '{
> $4="Christine"
> print $0}'
My name is Rich
要退出程序,只需按下Ctrl+D组合键来表明数据结束。
04. 从文件中读取程序
跟sed编辑器一样, gawk编辑器允许将程序存储到文件中,然后再在命令行中引用。
[root@ufo130 ~]# cat script2.gawk
{print $1 "'s home directory is " $6}
[root@ufo130 ~]# gawk -F: -f script2.gawk /etc/passwd
root's home directory is /root
bin's home directory is /bin
可以在程序文件中指定多条命令。
cat script3.gawk
{
text = "'s home directory is "
print $1 text $6
}
注意, gawk程序在引用变量值时并未像shell脚本一样使用美元符。
05. 在处理数据前运行脚本
gawk还允许指定程序脚本何时运行。默认情况下, gawk会从输入中读取一行文本,然后针对该行的数据执行程序脚本。有时可能需要在处理数据前运行脚本,比如为报告创建标题。BEGIN关键字就是用来做这个的。它会强制gawk在读取数据前执行BEGIN关键字后指定的程序脚本。
如果想使用正常的程序脚本中处理数据,必须用另一个脚本区域来定义程序。这么做时要小心,两段脚本仍然被认为是gawk命令行中的一个文本字符串。你需要相应地加上单引号。
[root@ufo130 ~]# gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}' data3.txt
06. 在处理数据后运行脚本
与BEGIN关键字类似, END关键字允许你指定一个程序脚本, gawk会在读完数据后执行它。
[root@ufo130 ~]# gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}
> END {print "End of File"}' data3.txt
从一个简单的数据文件中创建一份完整的报。
[root@ufo130 ~]# 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"
}
它还定义了一个叫作FS的特殊变量。这是定义字段分隔符的另一种方法。这样你就不用依靠脚本用户在命令行选项中定义字段分隔符了。
03. sed 编辑器基础
01. 替换标记
[root@ufo130 ~]# sed 's/test/trial/' data4.txt
This is a trial of the test script.
This is the second trial of the test script.
替换命令在替换多行中的文本时能正常工作,但默认情况下它只替换每行中出现的第一处。要让替换命令能够替换一行中不同地方出现的文本必须使用替换标记。替换标记会在替换命令字符串之后设置。
s/pattern/replacement/flags
- 数字,表明新文本将替换第几处模式匹配的地方
- g,表明新文本将会替换所有匹配的文本
- p,表明原先行的内容要打印出来
- w file,将替换的结果写到文件中
[root@ufo130 ~]# sed 's/test/trial/2' data4.txt
This is a test of the trial script.
This is the second test of the trial script.
[root@ufo130 ~]# sed 's/test/trial/g' data4.txt
This is a trial of the trial script.
This is the second trial of the trial script.
-n选项将禁止sed编辑器输出。但p替换标记会输出修改过的行。将二者配合使用的效果就是只输出被替换命令修改过的行。
[root@ufo130 ~]# sed -n 's/test/trial/p' data5.txt
This is a trial line
w替换标记会产生同样的输出,不过会将输出保存到指定文件中。sed编辑器的正常输出是在STDOUT中,而只有那些包含匹配模式的行才会保存在指定的输出文件中。
sed 's/test/trial/w test.txt' data5.txt
sed编辑器允许选择其他字符来作为替换命令中的字符串分隔符。
sed 's//bin/bash//bin/csh/' /etc/passwd
sed 's!/bin/bash!/bin/csh!' /etc/passwd
02. 使用地址
默认情况下,在sed编辑器中使用的命令会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,则必须用行寻址。
- 以数字形式表示行区间
- 用文本模式来过滤出行
两种形式都使用相同的格式来指定地址:
[address]command
也可以将特定地址的多个命令分组:
address {
command1
command2
command3
}
数字方式的行寻址
在命令中指定的地址可以是单个行号,或是用起始行号、逗号以及结尾行号指定的一定区间范围内的行。
[root@ufo130 ~]# sed '2s/dog/cat/' data1.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
[root@ufo130 ~]# 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
# 从某行开始到结尾,使用美元符$
[root@ufo130 ~]# 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
使用文本模式过滤器
必须用正斜线将要指定的pattern封起来,格式如下:
/pattern/command
[root@ufo130 ~]# grep Samantha /etc/passwd
Samantha:x:502:502::/home/Samantha:/bin/bash
[root@ufo130 ~]# sed '/Samantha/s/bash/csh/' /etc/passwd
Samantha:x:502:502::/home/Samantha:/bin/csh
sed编辑器在文本模式中采用了一种称为正则表达式的特性来帮助你创建匹配效果更好的模式。正则表达式允许创建高级文本模式匹配表达式来匹配各种数据。
命令组合
如果需要在单行上执行多条命令,可以用花括号将多条命令组合在一起。
[root@ufo130 ~]# 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.
[root@ufo130 ~]# sed '3,${
> s/brown/green/
> s/lazy/active/
> }' data1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick green fox jumps over the active dog.
The quick green fox jumps over the active dog.
03. 删除行
删除命令d名副其实,它会删除匹配指定寻址模式的所有行。使用该命令时要特别小心,如果你忘记加入寻址模式的话,流中的所有文本行都会被删除。
[root@ufo130 ~]# sed '3d' data6.txt
This is line number 1.
This is line number 2.
This is line number 4.
[root@ufo130 ~]# sed '2,3d' data6.txt
This is line number 1.
This is line number 4.
[root@ufo130 ~]# sed '3,$d' data6.txt
This is line number 1.
This is line number 2.
[root@ufo130 ~]# sed '/number 1/d' data6.txt
This is line number 2.
This is line number 3.
This is line number 4.
说明:记住,sed编辑器不会修改原始文件。你删除的行只是从sed编辑器的输出中消失了。原始文件仍然包含那些“删掉的”行。
也可以使用两个文本模式来删除某个区间内的行,但这么做时要小心。你指定的第一个模式会“打开”行删除功能,第二个模式会“关闭”行删除功能。
[root@ufo130 ~]# sed '/1/,/3/d' data6.txt
This is line number 4.
如果匹配的数据多次出现,则会多次触发删除动作。如果一直没匹配到结束模式,则整个数据流都被删掉了。特别危险!
04. 插入和附加文本
- 插入(insert)命令(i)会在指定行前增加一个新行
- 附加(append)命令(a)会在指定行后增加一个新行
它们不能在单个命令行上使用。你必须指定是要将行插入还是附加到另一行。格式如下:
sed '[address]command
new line'
[root@ufo130 ~]# echo "Test Line 2" | sed 'iTest Line 1'
Test Line 1
Test Line 2
[root@ufo130 ~]# echo "Test Line 2" | sed 'aTest Line 1'
Test Line 2
Test Line 1
在命令行中,一旦你输入了结尾的单引号,bash shell就会执行该命令。
[root@ufo130 ~]# echo "Test Line 2" | sed 'i
> Test Line 1'
Test Line 1
Test Line 2
这样能够给数据流中的文本前面或后面添加文本,但如果要向数据流内部添加文本呢?
要向数据流行内部插入或附加数据,你必须用寻址来告诉sed编辑器你想让数据出现在什么位置。可以在用这些命令时只指定一个行地址。可以匹配一个数字行号或文本模式,但不能用地址区间。这合乎逻辑,因为你只能将文本插入或附加到单个行的前面或后面,而不是行区间的前面或后面。
[root@ufo130 ~]# sed '3i
> This is an inserted line.' data6.txt
This is line number 1.
This is line number 2.
This is an inserted line.
This is line number 3.
This is line number 4.
[root@ufo130 ~]# sed '3a
> This is an appended line.' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an appended line.
This is line number 4.
[root@ufo130 ~]# sed '$a
> This is a new line of text.' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is a new line of text.
要插入或附加多行文本,就必须对要插入或附加的新文本中的每一行使用反斜线,直到最后一行。
[root@ufo130 ~]# sed '1i
> This is one line of new text.
> This is another line of new text.' data6.txt
This is one line of new text.
This is another line of new text.
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
05. 修改行
允许修改数据流中整行文本的内容。它跟插入和附加命令的工作机制一样,你必须在sed命令中单独指定新行。
[root@ufo130 ~]# sed '3c
> This is a changed line of text.' data6.txt
This is line number 1.
This is line number 2.
This is a changed line of text.
This is line number 4.
[root@ufo130 ~]# sed '/number 3/c
> This is a changed line of text.' data6.txt
This is line number 1.
This is line number 2.
This is a changed line of text.
This is line number 4.
注意,文本模式修改命令会修改它匹配的数据流中的任意文本行。
你也可以指定整个区间进行修改。
[root@ufo130 ~]# sed '2,3c
> This is a new line of text.' data6.txt
This is line number 1.
This is a new line of text.
This is line number 4.
06. 转换命令
是唯一可以处理单个字符的sed编辑器命令。转换命令格式如下。
[address]y/inchars/outchars/
转换命令会对inchars和outchars值进行一对一的映射。inchars中的第一个字符会被转
换为outchars中的第一个字符,第二个字符会被转换成outchars中的第二个字符。这个映射过程会一直持续到处理完指定字符。如果inchars和outchars的长度不同,则sed编辑器会产生一条错误消息。
[root@ufo130 ~]# 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.
转换命令是一个全局命令,也就是说,它会文本行中找到的所有指定字符自动进行转换,而不会考虑它们出现的位置。
[root@ufo130 ~]# echo "This 1 is a test of 1 try." | sed 'y/123/456/'
This 4 is a test of 4 try.
07. 回顾打印
- p命令用来打印文本行
- 等号(=)命令用来打印行号
- l(小写的L)命令用来列出行
打印行
在命令行上用-n选项,你可以禁止输出其他行,只打印包含匹配文本模式的行。
[root@ufo130 ~]# sed -n '/number 3/p' data6.txt
This is line number 3.
[root@ufo130 ~]# sed -n '2,3p' data6.txt
This is line number 2.
This is line number 3.
如果需要在修改之前查看行,也可以使用打印命令,比如与替换或修改命令一起使用。
[root@ufo130 ~]# sed -n '/3/{
> p
> s/line/test/p
> }' data6.txt
This is line number 3.
This is test number 3.
打印行号
等号命令会打印行在数据流中的当前行号。行号由数据流中的换行符决定。每次数据流中出现一个换行符,sed编辑器会认为一行文本结束了。
[root@ufo130 ~]# sed '=' data1.txt
1
The quick brown fox jumps over the lazy dog.
2
The quick brown fox jumps over the lazy dog.
3
The quick brown fox jumps over the lazy dog.
如果你要在数据流中查找特定文本模式的话,等号命令用起来非常方便。
[root@ufo130 ~]# sed -n '/number 4/{
> =
> p
> }' data6.txt
4
This is line number 4.
列出行
(小写的L)命令可以打印数据流中的文本和不可打印的ASCII字符。任何不可打印字符要么在其八进制值前加一个反斜线,要么使用标准C风格的命名法(用于常见的不可打印字符),比如t,来代表制表符。
[root@ufo130 ~]# sed -n 'l' data9.txt
Thistlinetcontainsttabs.$
制表符的位置使用t来显示。行尾的美元符表示换行符。如果数据流包含了转义字符,列出命令会在必要时候用八进制码来显示。
[root@ufo130 ~]# cat data10.txt
This line contains an escape character.
[root@ufo130 ~]# sed -n 'l' data10.txt
This line contains an escape character. a$
data10.txt 文本文件包含了一个转义控制码来产生铃声。当用cat命令来显示文本文件时,你看不到转义控制码,只能听到声音(如果你的音箱打开的话)。但是,利用列出命令,你就能显示出所使用的转义控制码。
08. 使用sed 处理文件
w命令用来向文件写入行。该命令的格式如下:
[address]w filename
filename可以使用相对路径或绝对路径,但不管是哪种,运行sed编辑器的用户都必须有文件的写权限。地址可以是sed中支持的任意类型的寻址方式,例如单个行号、文本模式、行区间。
写入文件
将数据流中的前两行打印到一个文本文件中。
[root@ufo130 ~]# 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.
[root@ufo130 ~]# cat test.txt
This is line number 1.
This is line number 2.
当然,如果你不想让行显示到STDOUT上,你可以用sed命令的-n选项。
sed -n '/Browncoat/w Browncoats.txt' data11.txt
从文件读取数据
读取(read)命令(r)允许你将一个独立文件中的数据插入到数据流中。读取命令的格式如下:
[address]r filename
filename 参数指定了数据文件的绝对路径或相对路径。你在读取命令中使用地址区间,只能指定单独一个行号或文本模式地址。sed编辑器会将文件中的文本插入到指定地址后。
[root@ufo130 ~]# 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.
[root@ufo130 ~]# sed '/number 2/r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is an added line.
This is the second added line.
This is line number 3.
This is line number 4.
如果你要在数据流的末尾添加文本,只需用美元符地址符就行了。
[root@ufo130 ~]# sed '$r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is an added line.
This is the second added line.
利用另一个文件中的数据来替换文件中的占位文本。
[root@ufo130 ~]# cat notice.std
Would the following people:
LIST
please report to the ship's captain.
[root@ufo130 ~]# sed '/LIST/{
> r data11.txt
> d
> }' notice.std
Would the following people:
Blum, R Browncoat
McGuiness, A Alliance
Bresnahan, C Browncoat
Harken, C Alliance
please report to the ship's captain.
最后
以上就是端庄鸡为你收集整理的Linux Shell 文本处理基础之sed、gawk的全部内容,希望文章能够帮你解决Linux Shell 文本处理基础之sed、gawk所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复