Linux三剑客是指的grep、sed、awk三个命令,grep主打查找功能,sed主要是编辑,awk主要是分割处理。
grep是global regular expressions print的缩写。grep命令能够在一个或者多个文件中搜索某一特定的字符模式,此模式可以是单一的字符、字符串、单词或句子。grep可以在文本中查找指定的字符串,是linux中最常用的文本处理工具之一。正则表达式的通配符如下:
*
: 将匹配0个或者多个字符。.
:将匹配任何一个字符,且只能是一个字符。[xyz]
:匹配方括号中的任意一个字符。[^xyz]
:匹配方括号中的任意一个字符。^
: 锁定行的开头。$
:锁定行的结尾。?
:匹配前面的子表达式0次或者1次。+
:匹配前面的子表达式1次或者多次。|
: 匹配于|
符号前或后的正则表达式。{n,m}
:最少匹配n次,最多匹配m次和BRE的区别是不需要加\。在基本的正则表达式中,使用通配符原本的意思,需要添加\
作为转义字符。
grep命令用来在每一个文件搜索特定的模式,当使用grep时,包含指定字符模式的每一行内容,都会被打印到屏幕上,但是使用grep命令并不改变文件中的内容。
grep命令格式:grep [选项] 模式 文件名
这里的模式,要么是字符串,要么是正则表达式。常用的选项如下表。
-c
:仅列出文件中包含模式的行数,即匹配到的总行数。
-i
:忽略模式中的字母大小写。
-l
:列出带有匹配行的文件名。
-n
:在每一行的最前面列出行号。
-v
:列出没有匹配模式的行。
-w
:把代表式当做一个完整的单字符来搜寻,忽略哪些部分匹配的行。
-color=auto
或者-color
:表示对匹配到的文本着色显示。
-o:只显示符号条件的字符串,但是不整行显示,每个符号条件的字符串单独显示一行。
-w:匹配整个单词,如果是字符串中包含这个单词,则不做匹配。
如果是搜索多个文件,grep命令的搜索结果只显示文件中发现匹配模式的文件名,如果搜索单个文件,grep命令的结果将显示每一个包含匹配模式的行。
sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供一组规则来编辑数据流。sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本中。
sed是操作、过滤和转换文本内容的强大工具,常用功能增删改查,过滤,取行。
sed命令的格式如下:sed [options] [sed-commands] [input-file]
-n
---- 抑制默认输出,-e
---- 执行多条编辑命令, -i
---- 直接在源文件中修改。sed是从文件或者管道中读取一行,放在模式空间中,进行处理,处理完输出一行,在读取一行,再处理一行。模式空间是sed内部的临时缓存,用于存放读取到的内容。
sed可以对单行或多行进行处理,如果在sed命令前面不指定地址范围,那么默认会匹配所有行。
sed的工作流程主要包括读取、执行和显示三个过程。
读取流程:sed从输入流(文件、管道、标准输入)中读取一行内容并存在到临时的缓冲区中(又称为模式空间)。
执行流程:默认情况下,所有的sed命令都在模式空间中顺利地执行,除非指定了行的地址,否则sed命令,将会在所有的行上依次执行。
显示流程:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空,在所有的文件内容都被完成处理之前,上述过程被反复执行,直至内容被处理完。
sed命令格式:
sed -e '操作' 文件1 文件2
sed -n -e '操作' 文件1 文件2
sed -f 脚本文件 文件1 文件2
sed -e -i '操作' 文件1 文件2
常用选项:
-e
或--expression
:表示用指定命令来处理输入的文本文件,只有一个操作命令时可以省略,一般在执行多个操作命令使用。-f
或--file
:表示用指定脚本文件来处理输入的文本文件。-h
或--help
:显示帮助。-n
或s --quiet:禁止sed编辑器输出,但可以与p命令一起使用完成输出。-i
:直接修改文本文件。-r
,-E
:使用扩展正则表达式-s
:将多个文件视为独立文件,而不是单个连续的长文件流。常用操作:
s
:替换指定字符(替换)。d
:删除指定的行(删除)。a
:在指定的行上一行增加一行指定内容(增加)。i
:在指定的上一行插入一行指定内容(插入)。c
:将选定行内容替换为指定内容(替换)。y
:字符转换,转换之后的字符长度必须相同。p
:打印,如果同时指定行,表示打印指定行,如果不指定行,则表示打印所有内容;如果有非打印字符,则以Ascii码输出。通常与_n选项一起使用。=
:打印行号。l
:答应数据流中的文本和不可打印的ASCII字符。使用sed命令查看:
方法一:sed ' ' /etc/shadow
root@chengyan-virtual-machine:~# sed ' ' /etc/shadow
root:$6$lvkzBBp4$EL4M3jGWlhVG73hngVOXVO1o3vtTaLIt7uNrlkC1:19201:0:99999:7:::
daemon:*:17379:0:99999:7:::
bin:*:17379:0:99999:7:::
sys:*:17379:0:99999:7:::
sync:*:17379:0:99999:7:::
games:*:17379:0:99999:7:::
man:*:17379:0:99999:7:::
lp:*:17379:0:99999:7:::
mail:*:17379:0:99999:7:::
方法二:sed -n 'p ' /etc/shadow
root@chengyan-virtual-machine:~# sed -n 'p ' /etc/shadow
root:$6$lvkzBBp4$EL4M3jGWlhVG73hngVOXVO1o3vtTaLIt7uNrlkC1:19201:0:99999:7:::
daemon:*:17379:0:99999:7:::
bin:*:17379:0:99999:7:::
sys:*:17379:0:99999:7:::
sync:*:17379:0:99999:7:::
games:*:17379:0:99999:7:::
man:*:17379:0:99999:7:::
lp:*:17379:0:99999:7:::
mail:*:17379:0:99999:7:::
查看指定行:
root@chengyan-virtual-machine:~# sed -n '3p' /etc/shadow
bin:*:17379:0:99999:7:::
使用正则表达式:匹配root开头的行
root@chengyan-virtual-machine:~# sed -n '/^root/p' /etc/shadow
root:$6$lvkzBBp4$EL4M3jGWlhVG73hngVOXVO1o3vtTaLIt7uNrlkC1:19201:0:99999:7:::
查看连续的行:查看3-6行的内容
root@chengyan-virtual-machine:~# sed -n '3,6p' /etc/shadow
bin:*:17379:0:99999:7:::
sys:*:17379:0:99999:7:::
sync:*:17379:0:99999:7:::
games:*:17379:0:99999:7:::
查看文件最后一行内容:
root@chengyan-virtual-machine:~# sed -n '$p' /etc/shadow
sshd:*:18964:0:99999:7:::
删除指定行并不是真正的删除,知识将删除了的结果显示出来,并不是真正的删除了文件中的内容,如果想要真正的删除文件中的内容需要添加选项-i
。
删除文本中的空行:sed '/^$/d' test.txt
root@chengyan-virtual-machine:~# cat -n test.txt
1
2 1
3 2
4 3
5 4
6
7 6
8 7
9 8
10 9
11
root@chengyan-virtual-machine:~# sed '/^$/d' test.txt
1
2
3
4
6
7
8
9
root@chengyan-virtual-machine:~#
删除指定行:
root@chengyan-virtual-machine:~# cat -n test.txt
1
2 1
3 2
4 3
5 4
6
7 6
8 7
9 8
10 9
11
root@chengyan-virtual-machine:~# sed '2d' test.txt
2
3
4
6
7
8
9
root@chengyan-virtual-machine:~#
命令格式:sed 指定行 's/需要替换的字符串/替换后的字符串/替换标记'
或者[address]s/pattern/replacement/flag
flag标记:
g
:表示要替换所有匹配的行。
w
:将替换后的结果保存到文档。
n
:1-512,表示指定要替换的字符串出现第几次时才进行替换。
w file
:将缓冲区中的内容写到指定的file文件中。
&
:用正则表达式匹配的内容进行替换。
\n
:匹配第n个子串,该子串之前在pattern中用\(\)
指定。
\
:转义。
将文件中的test替换为taget:
root@chengyan-virtual-machine:~# cat test1.txt
This is a test file to test replace sed command.
root@chengyan-virtual-machine:~# sed 's/test/taget/g' test1.txt
This is a taget file to taget replace sed command.
root@chengyan-virtual-machine:~#
在第二行下方增加:
root@chengyan-virtual-machine:~# cat test.txt
1
2
3
4
6
7
8
9
root@chengyan-virtual-machine:~# sed '2a ######' test.txt
1
######
2
3
4
6
7
8
9
root@chengyan-virtual-machine:~#
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据进行分析并产生报告时,显得尤为强大。简单的说就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分在进行各种分析处理。
命令格式:awk [选项] '脚本命令' 文件名
常用选项:
-F fs
:指定以fs作为输入行的分隔符,awk命令默认分隔符为空格或者制表符。-f file
:从脚本文件中读取awk脚本指令,以取代直接在命令行中输入指令。-v var=val
:在执行处理过程之前,设置一个变量var,并给其设备的初始值为val。awk的强大在于脚本命令,有两部分组成,分别是匹配规则和执行命令。
匹配规则{执行命令}
匹配规则用来指定脚本命令可以作用到文本内容中的具体行,可以使用字符串或者正则表达式指定。
整个脚本命令是用单引号括起来,而其中的执行命令部分需要用大括号括起来。
root@chengyan-virtual-machine:~# cat test.txt
1
2
3
4
6
7
8
9
root@chengyan-virtual-machine:~# awk '/^$/{print "Blank line"}' test.txt
Blank line
Blank line
Blank line
root@chengyan-virtual-machine:~#
其中,/^$/
是一个正则表达式,功能是匹配文本中的空白行,同时可以看到,执行命令使用的是print命令,此命令的功能是将指定的文本进行输出。
awk的主要特性之一就是处理文本文件中数据的能力,它会自动给一行中的每个数据元素分配一个变量。默认情况下,awk会将如下变量分配给它在文本行中发现的数据字段。
awk默认的字段分割符是任意的空白字符,在文本行中,每个数据字段都是通过子弹分割符换分的。awk在读取一行文本时,会用预定的字段分隔符换分每个数据字段。
root@chengyan-virtual-machine:~# cat data.txt
One line of test txt.
Two lines of test txt.
Three lines of test text.
root@chengyan-virtual-machine:~# awk '{print $1}' data.txt
One
Two
Three
root@chengyan-virtual-machine:~#
上面只用了$1
字段变量来表示“仅显示每行文本的第一个数据字段”。要读取采用了其他字段分隔符的文件,可以用-F
选项手动指定。
awk允许将多条命令组合称为一个正常的程序。要在命令行上的程序脚本中使用多条命令,只要在命令之间放个分号即可。
root@chengyan-virtual-machine:~# echo "My name is Rich" | awk '{$4="Christine";print $0}'
My name is Christine
root@chengyan-virtual-machine:~# awk '{
> $4="Christine";
> print $0
> }'
My name is Rich
My name is Christine
His name is wanghao
His name is Christine
当用了起始的单引号后,bash shell会使用>
来提示输入更多数据,可以在每行加一条命令,知道输入了结尾的单引号。因为没有在命令行中指定文件名,awk程序需要用户输入获得数据,因此当运行这个程序的时候,会一直等待用户输入文本,此时如果要退出程序,只需要输入CTRL+D即可。
root@chengyan-virtual-machine:~# cat awk.sh
{print $1"'s home directory is " $6}
root@chengyan-virtual-machine:~# awk -F : -f awk.sh /etc/passwd
root's home directory is /root
daemon's home directory is /usr/sbin
bin's home directory is /bin
sys's home directory is /dev
sync's home directory is /bin
games's home directory is /usr/games
man's home directory is /var/cache/man
在脚本文件中,可以指定多条命令,只要一条命令放在一行就行.
awk中还可以指定脚本命令运行的时机,默认情况下,awk会从输入中读取一行文本,然后针对该行的数据执行程序脚本,但有时可能需要在处理数据前运行一些脚本命令,这就需要使用BEGIN关键字。
BEGIN关键字会强制awk在读取数据前执行该关键字后指定的脚本命令。
root@chengyan-virtual-machine:~# awk 'BEGIN{print "The data file contents:"}
> {print $0}' data.txt
The data file contents:
One line of test txt.
Two lines of test txt.
Three lines of test text.
root@chengyan-virtual-machine:~#
这个脚本命令分为两部分,BEGIN部分的脚本指令会在awk命令处理函数前运行,而真正用来处理数据的是第二段脚本命令。
END关键字允许指定一些脚本命令,awk会在读取完数据后执行。
root@chengyan-virtual-machine:~# awk 'BEGIN{print "The data file contents:"}
{print $0}
END{print "End of file"}' data.txt
The data file contents:
One line of test txt.
Two lines of test txt.
Three lines of test text.
End of file
root@chengyan-virtual-machine:~#
在awk脚本程序中,支持使用变量来存取值,awk支持两种不同类型的变量,即内建变量和自定义变量。
内建变量是awk本身就创建好的,用户可以直接使用的变量,这些变量用来存放处理数据文件中的某些字段和记录的信息。自定义变量是awk支持用户自己创建的变量。
常见的内建变量包括数据字段变量($0,$1,$2,....
)和其他变量。
字符和记录分隔符变量:
FIELDWIDTHS
:由空格分割的一列数字,定义了每个数据字段的确切宽度。FNR
:当前输入文档的记录编号,常在有多个输入文档时使用。NR
:输入流的当前记录编号。FS
:输入字段分隔符。RS
:输入记录分隔符,默认为换行符\n。OFS
:输出字段分隔符,默认为空格。ORS
:输出字段分隔符,默认为换行符\n。环境信息变量:
ARGC
:命令行参数个数。ARGIND
:当前文件在ARGC中的位置。ARGV
:包含命令行参数的数组。CONVFMT
:数字的转换格式,默认值为%.6g。ENVIRON
:当前shell环境变量及其值组成的关联数组。ERRNO
:当前读取或关闭输入文件发生错误时的系统错误号。FILENAME
:当前输入文档的名称。FNR
:当前数据文件中的数据行数。IGNORECASE
:设成非0值时,忽略awk命令中出现的字符串的字符串大小。NF
:数据文件中的字段总数。OFMT
:数字的输出格式,默认值为%.6g。RLENGTH
:由match函数所匹配的子字符串的长度。TSTART
:由match函数所匹配的子字符串的起始位置。变量FS和OFS定义了awk如何处理数据流中的数据字段。
root@chengyan-virtual-machine:~# cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
root@chengyan-virtual-machine:~# awk 'BEGIN{FS=",";OFS="-"}{print $1,$2,$3}' data.txt
data11-data12-data13
data21-data22-data23
data31-data32-data33
root@chengyan-virtual-machine:~# awk 'BEGIN{FS=",";OFS="--"}{print $1,$2,$3}' data.txt
data11--data12--data13
data21--data22--data23
data31--data32--data33
root@chengyan-virtual-machine:~#
FIELDWIDTHS变量允许用户不依靠字段分隔符来读取记录,数据如果没有设置分隔符,而是放在特定列中,这种情况下,必须设定FIELDWIDTHS变量来匹配数据在记录中的位置。一旦设置了FIELDWIDTH变量,awk就会忽略FS变量,并根据提供的字段宽度来计算字段。
root@chengyan-virtual-machine:~# cat data1.txt
1005.3247596.37
115-2.349194.00
05810.1298100.1
root@chengyan-virtual-machine:~# awk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1.txt
1005.3247596.37
115-2.349194.00
05810.1298100.1
root@chengyan-virtual-machine:~#
一旦设置了FIELWIDTHS变量的值,就不能在改变了,所以并不适用于变长的字段。
变量RS和ORS定义了awk程序如何处理数据流中的字段,默认情况下,awk将RS和ORS设为换行符。默认的RS值标明,输入数据流中的每行新文本都是一条新纪录。
root@chengyan-virtual-machine:~# cat data2.txt
Riley Mullen
123 Main Street
Chicago,IL 60601
(312)555-1234
Frank Wiliams
456 Oak Street
Indianapolis,IN 46201
(317)555-9876
Haley Snell
4231 Elm Street
Detroit,MI 48201
(313)555-4938
root@chengyan-virtual-machine:~# awk 'BEGIN{FS="\n";RS=""}{print $1,$4}' data2.txt
Riley Mullen (312)555-1234
Frank Wiliams (317)555-9876
Haley Snell (313)555-4938
root@chengyan-virtual-machine:~#
FNR变量含有当前数据文件中已处理过的记录数,NR变量则含有已处理过的记录总数。
root@chengyan-virtual-machine:~# cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
root@chengyan-virtual-machine:~# awk '
> BEGIN{FS=","}
> {print $1, "FNR="FNR, "NR="NR}
> END{print "There were",NR,"records processed"}' data.txt data.txt
data11 FNR=1 NR=1
data21 FNR=2 NR=2
data31 FNR=3 NR=3
data11 FNR=1 NR=4
data21 FNR=2 NR=5
data31 FNR=3 NR=6
There were 6 records processed
root@chengyan-virtual-machine:~#
可以发现,当使用一个数据文件作为输入时,FNR和NR的值相同的,如果多个文件同时作为输入时,FNR的值会在处理每个数据文件时被重置,而NR的值则会继续计数知道处理完所有的数据文件。