Linux哲学思想中有一条就是Linux下一切皆文件。因此当我们操作Linux的时候,本质是在操作各种文件。因此掌握文本编辑的命令也是至关重要的,Linux提供了很多的文本编辑命令,以及被称为Linux"三剑客“的grep
、sed
和awk
命令。
一、cat命令
cat 命令( concatenate(连接、连续)的简写)用于连接文件并打印到标准输出设备上,也可以把几个文件内容附加到另一个文件中,即连接合并文件。
cat命令的语法格式如下
cat [option] filename
可用的选项:
选项 | 含义 |
---|---|
-A | 相当于 -vET 选项的整合,用于列出所有隐藏符号; |
-E | 列出每行结尾的回车符 $; |
-n | 对输出的所有行进行编号; |
-b | 和-n参数作用类似,但此选项表示只对非空行进行编号。 |
-T | 把 Tab 键 ^I 显示出来; |
-v | 列出特殊字符; |
-s | 当遇到有连续 2 行以上的空白行时,就替换为 1 行的空白行。 |
示例
- 把a.txt中的内容加上行号复制一份到b.txt
cat -n a.txt>b.txt
- 合并a.txt和b.txt中的内容,并不要空格加上行号之后追加到c.txt
cat -b a.txt b.txt>c.txt
二、head命令
head 命令可以显示指定文件前若干行的文件内容,其基本格式如下:
head [option] filename
常用可用的选项:
选项 | 含义 |
---|---|
-n K | 这里的 K 表示行数,该选项用来显示文件前 K 行的内容;如果使用 "-K" 作为参数,则表示除了文件最后 K 行外,显示剩余的全部内容。 |
-c K | 这里的 K 表示字节数,该选项用来显示文件前 K 个字节的内容;如果使用 "-K",则表示除了文件最后 K 字节的内容,显示剩余全部内容。 |
-v | 显示文件名; |
注意!如果没有指定具体显示的行数,默认显示就是前10行。下图是使用head命令查看tomcat中官方README.md的打印:
三、tail命令
tail命令的作用和head命令的作用正好相反,tail它可以从文件末尾查看文件内容。命令格式如下:
tail [option] filename
常用可用选项:
选项 | 含义 |
---|---|
-n K | 这里的 K 指的是行数,该选项表示输出最后 K 行,在此基础上,如果使用 -n +K ,则表示从文件的第 K 行开始输出(这个参数在过滤文本表头的时候非常有用)。 |
--c K | 这里的 K 指的是字节数,该选项表示输出文件最后 K 个字节的内容,在此基础上,使用 -c +K 则表示从文件第 K 个字节开始输出。 |
-f | 输出文件变化后新增加的数据。 |
同样地,tail命令如果在使用的时候没有指定行数,那么默认显示最后10行。
使用cat、head、tail组合
1、查看日志pro.log后100行数据
cat pro.log | tail -n 1000
2、查看日志pro.log100到300行的数据
cat pro.log | head -n 300 | tail -n 100
3、打印pro.log文件第1000行开始以后的内容
cat pro.log | tail -n +1000
4、打印pro.log文件第1000行开始之前的内容
cat pro.log | head -n 1000
四、grep命令
很多时候,我们并不需要列出文件的全部内容,而是从文件中找到包含指定信息的那些行,要实现这个目的,可以使用 grep 命令。
grep是global regular expressions print的简写,它能够在一个或多个文件中,搜索某一特定的字符模式(也就是正则表达式),此模式可以是单一的字符、字符串、单词或句子。grep家族一共有三个:grep、egrep和fgrep。grep在查找的时候,会有三种类似返回值:找到返回0,没找到返回1,没有找到指定文件返回2
1、grep命令的格式
grep [option] PATTERN filename
这里的Patterns支持正则表达式以及普通字符串,grep的可选参数众多,按照men
对grep提供的帮助,大致可以划分为以下几种:
(1)匹配选择
选项 | 含义 |
---|---|
-E | 开启扩展(Extend)的正则表达式,也就相当于egrep命令 |
-F | 解释PATTERN作为固定字符串的列表,由换行符分隔,其中任何一个都要匹配。也就相当于使用fgrep。 |
-G | 将PATTERN视为普通的表示法来使用。这个是默认值,也就是grep |
-P | 将PATTERN解释为Perl正则表达式。 |
(2)匹配控制选项
选项 | 含义 |
---|---|
-e PATTERN | 使用指定字符串做为查找文件内容的模式。 |
-f FILE | 指定规则文件,其内容含有一个或多个规则样式,让grep查找符合规则条件的文件内容,格式为每行一个规则样式。 |
-i | 忽略大小写(ignore case)。 |
-v | 只打印没有匹配的,而匹配的反而不打印 |
-w | 被匹配的文本只能是单词,而不能是单词中的某一部分 |
-x | 只显示全列符合的列。 |
-y | 此参数的效果和指定"-i"参数相同。 |
(3)输出控制
选项 | 含义 |
---|---|
-c, --count | 显示总共有多少行被匹配到了,而不是显示被匹配到的内容 |
--color | 将匹配到的内容以颜色高亮显示。 |
-L | 列出文件内容不符合指定的样式的文件名称。 |
-l | 列出文件内容符合指定的样式的文件名称。 |
-o | 只显示匹配PATTERN 部分。 |
-q, --quiet, --silent | 静默。即使有匹配的内容也不显示出来。 |
-s | 不显示错误信息。 |
-b | 在显示符合样式的那一行之前,标示出该行第一个字符的编号 |
-H | 在显示符合样式的那一行之前,表示该行所属的文件名称。 |
-h | 在显示符合样式的那一行之前,不标示该行所属的文件名称。 |
-Z, - -null | 输出零字节(ASCII NUL字符),而不是通常在文件名后的字符。 例如,grep -lZ在每个文件名之后输出一个零字节,而不是通常的换行符。 即使存在包含不寻常字符(例如换行符)的文件名,此选项也可以使输出明确。 |
-n | 显示行号 |
(4)文本行控制
选项 | 含义 |
---|---|
-A NUM, - -after-context=NUM | 显示匹配到的字符串所在的行及其后n行 |
-B NUM, - -before-context=NUM | 显示匹配到的字符串所在的行及其前n行 |
-C NUM, - -context=NUM | 显示匹配到的字符串所在的行及其前后各n行 |
- -group-separator=SEP | 使用SEP作为组分隔符。 默认情况下,SEP是双连字符(-)。- |
- -no-group-separator | 使用空字符串作为组分隔符。 |
2、正则表达式
grep命令支持使用正则表达式,正则表达式又有基本正则表达式和扩展正则表达式的区别。
(1)基本正则表达式
匹配字符:
.
:任意一个字符。
[abc]
:表示匹配一个字符,这个字符必须是abc中的一个。
[a-zA-Z]
:表示匹配一个字符,这个字符必须是a-z或A-Z这52个字母中的一个。
[\^123]
:匹配一个字符,这个字符是除了1、2、3以外的所有字符。
对于一些常用的字符集,系统也做了定义:
[A-Za-z]
等价于 [[:alpha:]]
[0-9]
等价于 [[:digit:]]
[A-Za-z0-9] 等价于 [[:alnum:]]
tab,space
等空白字符 [[:space:]]
[A-Z]
等价于 [[:upper:]]
[a-z]
等价于 [[:lower:]]
标点符号 [[:punct:]]
匹配次数:
\\{m,n\\}
:匹配其前面出现的字符至少m次,至多n次。
\?
:匹配其前面出现的内容0次或1次,等价于{0,1}。 \*
:匹配其前面出现的内容任意次,等价于{0,},所以 ".*" 表述任意字符任意次,即无论什么内容全部匹配。
匹配多次,在使用的时候\
一定不能丢
匹配任意次
位置锚定:
^
:锚定行首
\$
:锚定行尾。技巧:"^$"用于匹配空白行。
\b或\<
:锚定单词的词首。如"\blike"不会匹配alike,但是会匹配liker
\b或\>
:锚定单词的词尾。如"\blike\b"不会匹配alike和liker,只会匹配like
\B
:与\b作用相反。
匹配以某个字符(串)开始的行
匹配以某个字符(串)结束的行
分组及引用:
\\(string\\)
:将string作为一个整体方便后面引用
\1
:引用第1个左括号及其对应的右括号所匹配的内容。
\2
:引用第2个左括号及其对应的右括号所匹配的内容。
\n
:引用第n个左括号及其对应的右括号所匹配的内容。
匹配开头字符和结束字符相同的行
(2)扩展正则表达式
扩展正则正则表达式需要加-E
或者配合egrep使用,基本的东西和基本正则表达式一样,只是扩展了一些内容,具体如下:
匹配字符:这部分和基本正则表达式一样
匹配次数:
\*
:和基本正则表达式一样
?
:基本正则表达式是?,二这里没有\。
{m,n}
:相比基本正则表达式也是没有了\。比如,{1,3}表示匹配1至3次;{3}表示匹配3次
+
:匹配其前面的字符至少一次,相当于{1,}。
位置锚定:和基本正则表达式一样。
分组及引用:
(string)
:相比基本正则表达式也是没有了\。
\1
:引用部分和基本正则表达式一样。
\n
:引用部分和基本正则表达式一样。
逻辑选择
a|b
:匹配a或b。比如,/^([0-9]{3}-|([0-9]{3}) )/ 表示匹配xxx-或(xxx)的数字串
3、grep基本用法案例
其实grep的输入不一定非要是文件,也可以是标准输入或者管道,比如:
- grep "root",和匹配标准输入
- 使用grep查看指定进程 :
ps -ef |grep 进程名
或pa -aux |grep 进程名
- 过滤当前目录下的文件夹
- 在网络配置文件 /etc/sysconfig/network-scripts/ifcfg-ens33 中检索出所有的 IP
grep 命令的功能非常强大,通过利用它的不同选项以及变化万千的正则表达式,可以获取任何我们所需要的信息。这里所介绍的 grep 命令,只介绍了它的一部分基础知识,比如说,grep 命令可用的选项还有很多,且用法也五花八门,不过对于初学者来说,本节所介绍的内容已经足以应付多数 Linux 系统的日常工作了。
五、sed命令
我们知道,Vim 采用的是交互式文本编辑模式,你可以用键盘命令来交互性地插入、删除或替换数据中的文本。但这里要讲的 sed 命令不同,它采用的是流编辑模式,最明显的特点是,sed是一种在线的、非交互式的编辑器,它-次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为模式空间
( pattern space),接着 用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。sed的工作流程如下图所示:
1、sed 命令的基本格式
#直接执行sed命令
sed [OPTION] COMMAND FILE
或
#执行一个脚本中(scriptfile)的sed命令
sed [OPTION] -f scriptfile FILE #不推荐
2、sed常用的选项参数(sed OPTION)
选项 | 含义 |
---|---|
-e 脚本命令 | 该选项会将其后跟的脚本命令添加到已有的命令中。 |
-f 脚本命令文件 | 该选项会将其后文件中的脚本命令添加到已有的命令中。一般不推荐使用 |
-n | 默认情况下,sed 会在所有的脚本指定执行完毕后,会自动输出处理后的内容,而该选项会屏蔽启动输出,需使用 print 命令来完成输出。 |
-i | 此选项会直接修改源文件,要慎用。 |
-r | 支持扩展正则表达式 |
特别需要注意的是,sed与grep不同,它的返回值0并不能表示它有没有修改成功,只有当发生语法错误的时候才会返回1。
3、sed命令参数(sed COMMAND)
命令参数 | 功能 |
---|---|
a | 在定位行号后附加新文本信息 |
i | 在定位行号后插入新文本信息 |
d | 删除匹配的行 |
c | 用新文本替换匹配的文本 |
s | 使用替换模式替换匹配的文本 |
g | 对数据中所有匹配到的内容进行全局替换,如果没有 g,则只会在第一次匹配成功时做替换操作 |
p | 打印与替换命令中指定的模式匹配的行。此标记通常与 -n 选项一起使用。 |
q | 结束或退出sed |
n | 1~512 之间的数字,表示指定要替换的字符串出现第几次时才进行替换,例如,一行中有 3 个 A,但用户只想替换第二个 A,这是就用到这个标记; |
r | 读取文件到缓冲区 |
**w ** | 将缓冲区中的内容写到指定的 file 文件中 |
h | 把模式空间中的内容复制到暂存空间 |
H | 把模式空间中的内容追加到暂存空间 |
x | 交换模式空间和暂存空间的内容 |
4、sed基本用法
sed的命令中支持使用正则表达式,但是用到扩展正则表达式的时候必须结合-r选项,并且正则表达式必须写在双斜线//
之间,下面来演示一下sed命令的基本用法:
(1)不使用任何COMMANDsed -r "" passwd
(2)让sed参数静默,不输出内容 sed -rn "" passwd
(3)通过COMMAND让sed输出内容 sed -rn "p" passwd
(4)使用正则表达式让sed打印root开头的行 sed -rn "/^root/p" passwd
(5)全局匹配并替换 sed -r "s/要替换的串/目标串/g" FILE
(6)忽略大小写全局替换sed -r "s/要替换的串/目标串/gi" FILE
5、sed扩展(高级)用法
5.1 sed定址操作
地址用于决定对哪些行进行编辑。地址形式可以是数字、正则表达式或二者的结合。如果没有指定地址, sed将处理输入文件中的所有行。
- 删除命令:d
#删除passwd文件中的所有行
sed -r "d" passwd
#删除passwd文件的第4行
sed -r "4d" passwd
#删除passwd文件的1~3行
sed -r "1,3d" passwd
#删除passwd文件第5行到最后一行
sed -r "5,$d" passwd
#删除passwd文件中root开头的行
sed -r "/^root/d" passwd
#从root开头的行开始总共删除5行
sed -r "/^root/,5d" passwd
#从root开头的行开始,再删除5行(把root那一行抛开,再加5行删除)
sed -r "/^root/,+5d" passwd
#删除所有奇数行
sed -r "1~2d" passwd
#删除素有偶数行
sed -r "0~2d" passwd
- 查找命令:s
#全文中搜索并替换admin为root
sed -r "s/admin/root/g" passwd
#全文替换行开始的admin为root
sed -r "s/admin/root/g" passwd
#注释第1~5行
sed -r "1,5s/(.*)/#\1/g" passwd
或
#&表示已经匹配的那些内容,可以直接使用
sed -r "1,5/(.*)/#&/g"
- 文件读入命令:r
#passwd读到第2行的时候去读取文件/etc/passwd
sed -r "2r /etc/hosts" passwd
- 文件写出命令:w
#将root开头的行写入当前目录下的a.txt文件
sed -r "/^root/w a.txt" passwd
- 追加、插入、替换命令:a、i、c
#处理到第4行的时候,在第4行后追加1111111
sed -r "4a\1111111" passswd
#在含有root的行后面追加111111
sed -r "/root/a\111111" passwd
#在第4行前插入222233
sed -r "4i\222233" passwd
#替换含有root的行尾33333
sed -r "/root/c\33333" passwd
六、awk命令
awk是一个强大的文本分析工具(严格来说是一种编程语言),相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
它之所以叫 AWK 是因为其取了三位创始人 $Alfred Aho$,$Peter Weinberger$, 和 $Brian Kernighan$ 的 Family Name 的首字符。
1、awk的基本语法格式
awk [options] 'COMMAND' FILE
awk常用选项参数:
选项 | 含义 |
---|---|
-F fs | 指定以 fs 作为输入行的分隔符,awk 命令默认分隔符为空格或制表符。 |
-f file | 从脚本文件中读取 awk 脚本指令,以取代直接在命令行中输入指令。 |
-v var=val | 在执行处理过程之前,设置一个变量 var,并给其设备初始值为 val。 |
awk的COMMAND
部分由两部分组成,分别为匹配规则和执行命令,如下所示:
'匹配规则{执行命令}'
这里的匹配规则,和 sed 命令中的COMMAND
部分作用相同,用来指定命令可以作用到文本内容中的具体行,可以使用字符串或者正则表达式(比如 /root/,表示查看含有 root字符串的行)指定。另外需要注意的是,整个COMMAND部分必须是用单引号(''
)括起,而其中的执行命令部分需要用大括号({}
)括起来。
在 awk 程序执行时,如果没有指定执行命令,则默认会把匹配的行输出;如果不指定匹配规则,则默认匹配文本中所有的行。
2、awk使用位置参数变量
awk 的主要特性之一是其处理文本文件中数据的能力,它会默认自动把一行数据按空白字符(例如空格或制表符)分隔,并给每段数据一个位置参数($1
、$2
.....)。
默认情况下,awk 会将如下变量分配给它在文本行中发现的数据字段:
- $0 代表整个文本行;
- $1 代表文本行中的第 1 个数据字段;
- $2 代表文本行中的第 2 个数据字段;
- $n 代表文本行中的第 n 个数据字段。
前面说过,在 awk 中,默认的字段分隔符是任意的空白字符(例如空格或制表符)。 在文本行中,每个数据字段都是通过字段分隔符划分的。awk 在读取一行文本时,会用预定义的字段分隔符划分每个数据字段。
这是使用默认的空白字符作为分隔符,我们还可以使用-F
选项参数指定分隔符,比如下图以.
(点)作为分隔符:
3、awk COMMAND中使用多个命令
awk 允许将多条命令组合成一个正常的程序。要在命令行上的程序脚本中使用多条命令,只要在命令之间放个分号(;
)隔开即可,例如:
4、awk BEGIN关键字
默认情况下,awk 会从输入中读取一行文本,然后针对该行的数据执行程序命令,但有时可能需要在处理数据前运行一些程序命令,这就需要使用 BEGIN
关键字。
BEGIN会强制awk在读取文本之前执行BEGIN脚本块的命令,例如:
注意!BEGIN命令和普通命令应该写在同一个单引号(
''
)内。
5、awk END关键字
END关键字和BEGIN关键字的作用相反,它允许awk在读取完数据执行执行他们,例如:
了解BEGIN和END后,我们可以大致总结出awk的工作流程:先执行BEGIN,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。
6、awk的变量
awk的变量分为内置变量和自定义变量;内置变量就是awk预定义好的、内置在awk内部的变量,而自定义变量就是用户定义的变量。
(1)awk内置变量
- FS(Field Separator):输入字段分隔符, 和
-F
参数作用类似,默认为空白字符 - OFS(Out of Field Separator):输出字段分隔符, 默认为空白字符
- RS(Record Separator):输入记录分隔符(输入换行符), 指定输入时的换行符,默认是换行符
- ORS(Output Record Separate):输出记录分隔符(输出换行符),输出时用指定符号代替换行符,默认是换行符
- NF(Number for Field):当前行的字段的个数(即当前行被分割成了几列)
- NR(Number of Record):行号,输入记录的总的行号。
- FNR:awk可以同时处理多个文件,因此awk提供此变量用于获取各文件分别计数的行号
- ARGC:命令行参数的个数
- ARGV:数组,保存的是命令行所给定的各参数
-
FILENAME:awk浏览的文件名
此外,$0变量是指整条记录。$1表示当前行的第一个字段,$2表示当前行的第二个字段,......以此类推。
统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
在命令中,我们首先使用内置命令FS定义了行分隔符为分号,之后awk开始逐行处理文件,使用内置变量获得文件名(FILENAME)、行号(NR)、每行的列数(NF)以及整行的内容($0),最后完成打印动作。
(2)awk自定义变量
在awk中自定义变量有两种方式
- 使用-v参数在COMMAND外部定义
一般格式:
-v varName=value #变量名严格区分大小写
自定义的变量在awk的COMMAND中可以直接使用,不需要向shell脚本那样在变量名前加上$
同时使用-v参数也可以接受shell变量的值
- 直接在COMMAND内部定义并使用
统计/etc/passwd的账户人数
awk '{count++} END{print "The user counts are: "count}'
变量默认初始化为0,但是当初始值不为0的时候可以使用=
赋值
awk 'BEGIN{sum=1000;print sum"/"3"="sum/3}'
7、awk的格式化输出
awk中同时提供了print和printf两种打印输出的函数。其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
统计磁盘可用空间大于10000字节的分区
(1)使用print函数
print函数会自动输出一个换行,一般我们都需要指定输出的格式
df -P | tail -n +2 | awk '$4>100000{print $1"\t"$4}'
(2)使用printf函数
printf函数的使用方式和C语言的printf函数类似,使用的时候参考C语言的语法格式就可以了
df -P | tail -n +2 | awk 'BEGIN{printf("%-25s %-15s\n","Filesystem","Aviable")} $4>10000{printf("%-25s %-15s\n",$1,$2)}'
8、awk 条件语句
awk中的条件语句是从C语言中借鉴来的,关键字和使用方法参考C语言就可以了,下面给出一些用法示例:
#if语句
awk '{if(Condition){statement;statement;}}' FILE
#if else语句
awk '{if(Condition){statement;statement} else{statement;statement}}' FILE
#if else-if else语句
awk '{if(Condition){statement;statement} else if(Conditon){statement;statement} else{statement;statement}}' FILE
统计某个文件夹下的文件占用的字节数,过滤4096大小的文件(一般都是文件夹):
ll | awk -v pwd=`pwd` 'BEGIN{size=0;print "start size is: "size} {if($5!=4096){size+=$5}} END{print "\nThe total used size of " pwd " is: "size}'
9、awk 循环语句
awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。用的时候直接用就好了,没啥特别的。
(1)for语句
#for语句使用模板
awk '{for(初始值;条件;步长){statement}}'
(2)while语句
#while语句使用模板
awk '{while(条件){statement}}'
(3)do-while语句
awk '{do{statement}while(条件)}'
10、awk的数组
因为awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key/value应用hash的表格里。由于hash不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,awk也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。
数组使用的语法格式:
array_name[index]=value
AWK 可以使用关联数组这种数据结构,索引可以是数字或字符串。
AWK关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。
显示/etc/passwd的账户
awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
11、awk的正则匹配
awk还支持正则匹配,正则表达式的语法规则参考上面grep命令的正则语法(通用的),不过需要注意的是:awk的匹配语句要写在//
内部才可以被awk识别。
示例 给定一个包含电话号码列表(一行一个电话号码)的文本文件 file.txt,写一个 bash 脚本输出所有有效的电话号码。
你可以假设一个有效的电话号码必须满足以下两种格式: (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一个数字)
这个例子可以使用正则表达式配合grep -P
、sed
和awk
,这里使用awk来实现
#!/bin/bash
awk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt
awk编程的还有很多内容,这里只罗列简单常用的用法,更多请参考http://www.gnu.org/software/gawk/manual/gawk.html