竹笋

首页 » 问答 » 灌水 » shell中的文本处理工具虫虫搜奇
TUhjnbcbe - 2023/2/14 5:24:00
湖南白癜风医院 http://hunan.ifeng.com/a/20170705/5797804_0.shtml

在Linux世界一切皆文件,而且绝大多数都是文本文件。Shell是强大的用户界面,其强大之处在于Shell中自带了大量的文本处理工具,而且这些工具可以通过通道串联起来形成流式处理线。这些命令使执行文本处理分析,在不同格式,过滤器行之间转换数据等工作变得轻而易举。

*nix界的一个哲学是专心做好一件事。

处理文本时候,基本做法是将遇到的复杂问题化整为零,化繁为简分解为一系列较小的问题,然后使用专门工具解决之。

得Linux者得天下,得Shell者得Linux,要得Shell首先要搞会文本处理工具(命令)。本文中虫虫给大家介绍Shell中常见的文本处理命令。这些命令中的每一个都旨在解决一个小问题。但是,可以结合他们完成现实中绝大多数的任务。本文首先介绍常见基本命令(工具)的使用方法,第二部分介绍一些结合这些命令的实际处理例子。本文旨在抛砖引玉,对于每一个工具的详细用法,建议man一下他们的帮助文档,这才是实际使用中最普遍的做法。

基本命令

cat

cat命令是我们最常用的工具,用于打印文件的内容在屏幕上,支持多个文件。

head

head打印文件中的头部,默认为前10行,可以通过-n加一个数字制定需要打印的行数。对一个大文件数据,只看文件的一部分内容用head非常有用,而且可以高性能快速显示。

head-n2host-info.sh

#!/bin/bash

tail

tail和head相反,打印文件中的最后n行。如果不制定-n参数默认为最后10行。tail在分析日志文件时候最常用,因为最新的日志都是附加到日志文件后面的。

tailhost-info.sh

echo---------可用内存------------------------------------------

free-m

echo-e\n

echo---------磁盘信息------------------------------------------

df-h

echo-e\n

echo---------内核版本-------------------------------------------

uname-a

echo-e\n

echo------------------------------------------------------------

如果要打印位于第n行(包括在内)之后的文件中的所有行,则可以使用-n+数字为参数,表示打印数字行后的所有内容。

tail-n+17host-info.sh

echo-e\n

echo------------------------------------------------------------

由于脚本文件有18行,因此tail-7+42仅在文件中打印第17行和第18行。

同时-n后也可以加负数整数,表示从后算起多少行,比如

tail-n-2host-info.sh的内容和tail-n+17host-info.sh打印的内容一样。

tail还有一个最常见的选项是-f或--follow显示文件中的最后10行,并实时显示当前写入文件的内容。要实时查看日志文件内容时候用tail-f

less

less可以对文件和输入流的文本以分页形式显示。并且支持通过空格、上下健在显示内容间移动。并且支持一些一些vim中的操作比如g和GG移动到开头和结尾,使用/和?加关键字搜索。

对应的,可能很多人爱用的more命令,对比cat、more和less用法,见下表:

wc

wc用来用统计字符、单词和行计数,支持文件或输入流统计。

-c表示统计字符:

wc-whost-info.sh

36host-info.sh

-w表示单词:

wc-whost-info.sh

36host-info.sh

-l表示行数:

wc-lhost-info.sh

18host-info.sh

不指定参数,会统计三个数:

wchost-info.sh

host-info.sh

如果文本数据通过管道输入或重定向到,则仅只会显示统计数。

cathost-info.sh

wc-l

18

wc-lhost-info.sh

18

cut

cut用来剪切出(按列)文件或者输入流文本的一部分。cut通过使用选项-d定义边界字符(将两列分隔),用-f选项加数字表示需要显示的列。

下面的命令,提取nginx访问日志第三列内容。

cut-d--f3access.log

-f选项支持设定多列,比如-f1,3选项显示第一列和第三列:

cut-d--f1,3access.log

paste

paste用来将两个不同的文件合并到一个多列文件中。

默认情况下,paste使用制表符(/t)分隔符,可以使用-d选项设定。

paste的一种常见用法是paste使用给定的定界符(使用-s和-d参数的组合)来连接流或文件中的所有行,相当于对行反转。

paste-s-d:tiangan

甲:乙:丙:丁:戊:己:庚:辛:壬:癸

如果-指定为输入文件,表示从stdin读取。

catdizhi

paste-s-d:-

子:丑:寅:卯:辰:巳:午:未:申:酉:戌:亥

sort

sort,对参数文件或输入进行排序。

sorttiangan

注意中文排序用的汉字unicode编码顺序(10天干中文unicode码为\u\u4e59\u4e19\u4e01\ua\u5df1\u5e9a\u8f9b\u58ec\u)

sort-r执行反向排序。

sort-n通过按字段的算术值对它们进行排序来执行数字排序。

catnumber

10

11

93

23

5

6

7

8

9

sortnumber

10

11

23

5

6

7

8

9

93

sort-nnumber

5

6

7

8

9

10

11

23

93

大家看出来区别了么。

uniq

uniq对文件或输入流中相同的行进行合并。

catnumber1

1

3

1

5

6

1

2

1

uniqnumber1

1

5

6

1

2

1

可以注意到uniq只能合并相邻的相同行,所以结果中并不是把所有内容为1的行都合并了。要合并文件中所有的行,首先应该对行内容进行排序,保证相同的行都在一起

sortnumber1

uniq

1

2

5

6

-c选项,用来统计合并相同行的次数。

sortnumber1

uniq-c

51

12

15

16

uniq-u仅在其输入中显示唯一行。

sortnumber1

uniq-u

2

5

6

实际中uniq常结合sort使用与结合使用来处理文本文件,来去除日志文件的重复行。

tr

tr代表translation,它执行一对一替换将目标字符代替为替换字符。它适用于字符或字符类,例如小写字母,可打印字符,空格,字母数字等。

trchar1char2将所有出现的事件char1从其标准输入转换为char2。

echoChongchongisNumberOne!

troO

ChOngchOngisNumberOne!

tr也可以使用[:class:]符号来翻译字符类,比如:

[:space:]代表所有类型的空格。下面命令把空格替换为,。

echoChongchongisNumberOne!

tr[:space:],

Chongchong,is,Number,One!,%

注意,%输出末尾的字符表示缺少结尾的换行符。上一行的换行符也被转换为逗号。

[:lower:]表示小写字母,对应的[:upper:]表示大写字母。所以大小转换可以用下命令:

echoChongchongisNumberOne!

tr[:lower:][:upper:]

CHONGCHONGISNUMBERONE!

echoChongchongisNumberOne!

tr[:upper:][:lower:]

chongchongisnumberone!

tr-cSET1SET2将不在SET1中的字符转换为SET2中的字符。以下示例将所有非元音替换为空格。

echoChongchongisNumberOne!

tr-c[abc]

cb%

tr-d删除匹配的字符,而不是替换它们。等价于trchar。

echoChongchongisNumberOne!

tr-d[:lower:]

CNO!

tr也可以使用符号替换字符范围,例如a和e之间的所有字母,或1和8之间的所有数字s-e,其中s表示起始字符,e表示结束字符。

echoChongchongisNumberOne!

tra-ex

ChongxhongisNumxxrOnx!

echo5cjalp34oi

tr1-4x

5cjalxxpxxoi

tr-sstring1将任何多次出现的字符合并为一个。常用于清除字符串中多余的空格。

echoChongchongisNumberOne!

tr-s

ChongchongisNumberOne!

fold

fold以指定的宽度,折截文本显示,例如确保文本适合较小尺寸的显示。

fold-wn在n字符处截断。

paste-stiangan

fold-w20

甲乙丙

丁戊

己庚

辛壬

-s选项旨在空格字符时候才会截断。

paste-stiangan

fold-s-w20

甲乙

丙丁

戊己

庚辛

壬癸

grep

grep是文本行过滤的瑞士*刀,文本处理三剑客之一(grep,sed,awk)。它对给定的模式进行行匹配过滤,支持正则表达式。

grep查找host-info.sh文件中出现echo的行:

grepechohost-info.sh

echo---------主机名--------------------------------------------

echo-e\n

echo---------系统信息------------------------------------------

echo-e\n

echo---------可用内存------------------------------------------

echo-e\n

echo---------磁盘信息------------------------------------------

echo-e\n

echo---------内核版本-------------------------------------------

echo-e\n

echo------------------------------------------------------------

grep对文件进行搜索,也可以对管道传递的文本流进行搜索。所以,可以链接多个grep命令以进一步过滤文本。

grepechohost-info.sh

grep\-e

echo-e\n

echo-e\n

echo-e\n

echo-e\n

echo-e\n

grep-v执行反向匹配,它会去掉和模式匹配的行,显示不匹配的行。

grep-vechohost-info.sh

#!/bin/bash

hostnamectl

uptime

free-m

df-h

uname–a

grep-i执行不区分大小写的匹配。

grep-l仅列出包含匹配项的文件。

grep-lechohost-info.sh

host-info.sh

grep-c统计找到模式的次数。

grep-cechohost-info.sh

11

grep-r在当前工作目录及其下的所有子目录中递归搜索文件。

grep-w只匹配整个单词。

sed

sed是一种非交互式流式编辑器,文本三剑客的老二。用于逐行地对其输入流执行文本转换。它可以从给出的文件或者管道中输入内容,并将结果输出。

sed命令的格式:

[address[,address]]function[arguments]

虽然sed可以执行许多功能,此处,我们仅介绍文本替换,这是sed最常用的方法。

一个sed替换命令如下:

s/样式/替换/[选项]

我们替host-info.sh中的echo为print:

seds/echo/print/ghost-info.sh

g(对于global)选项表示替换每一行中所有出现模式。

如果替换模式的搜索中包含/,sed可以让我们自定义指定其他分隔符/,比如

seds#echo#print#ghost-info.sh

通过指定地址,可以告诉sed在制定的行范围,地址范围可以用start,end,其中end可以是一个行号或用表示文件的最后一行,实施替换,比如:

sed2s#echo#print#ghost-info.sh

sed2,s#echo#print#ghost-info.sh

默认情况下,将sed其结果显示在中stdout,但可以使用该-i选项编辑原始文件。

awk

awk文本三剑客的老幺,不仅仅是文本处理工具,也是一门强大的编程语言。awk真正擅长的事情,是将文件拆分为多个列,当文件中包含空格和制表符的混合匹配时,非常有用。

awk{print1}host-info.sh

打印host-info.sh脚本中的第一列

#!/bin/bash

echo

hostnamectl

echo

echo

uptime

echo

echo

free

echo

echo

df

echo

echo

uname

echo

echo

psaux

awk{printNF,1,4}

用来显示系统当前执行进程的执行命令、CPU和内存占有量,其中NF表示打印最后一列。

实例展示

显示当前连接的tcp各个状态的连接数

netstat-nat

awk{printNF}

sort

uniq-c

1CLOSE_WAIT

1established)

ESTABLISHED

33LISTEN

1State

22SYN_SENT

TIME_WAIT

这是网络服务器网络调试中最常用的命令之一,各个状态连接数及其比例往往反应一台服务器业务处理情况。如果服务配置,内核参数上有问题,或者服务器遭受攻击等都可以通过这些状态连接数反应出来。

打印某个网卡的IPv4地址

ifconfigeth0

grep-vinet6

grepinet

awk{print2}

.26.70.

也可以用ip命令:

ipaddrshoweth0

grep-vinet6

grepinet

awk{print2}

.26.70./20

注意ip和ifconfig在显示上略有区别,ip命令结果中把Ip和掩码用位形式显示。

上述命令中先grep-v去除了ipv6的地址信息,然后筛选inet(ipv4)的行,然后打印第二列就是ip地址。我们也可以不用grep用awk直接筛选得出结果:

ifconfigeth0

awk1==inet{print2}

.26.70.

从配置文件中提取值

grepeditor=~/.gitconfig

cut-d=-f2

seds///g

/usr/bin/vim

我们editor=在当前用户的git配置文件中查找该值,然后用=分割cut结果,获得第二列,并删除该列两边的任何空格。提取的依次显示过程如下:

grepeditor=~/.gitconfig

editor=/usr/bin/vim

grepeditor=~/.gitconfig

cut-d=-f2

/usr/bin/vim

grepeditor=~/.gitconfig

cut-d=-f2

seds///

/usr/bin/vim

从日志文件中提取IP地址

统计nginx访问日志中,Useragent为Java/1.8.0-internal(可能为非法爬虫或者Ddos攻击源)并显示10个最大的IP。

grepJava/1.8.0-internalaccess.log

awk{print1}

sort

uniq-c

sort-nr

head-n10

.66..51

.22.74.

.3..

.21..

.3.3.

..64.

...

...

..62.

..71.48

重命名源文件中的函数

假设我们正在一个代码项目中,并且想在代码文件中重命名一个名字不佳的函数(或类,变量等)。我们可以通过使用来执行此操作sed-i,该命令在文件中执行就地替换。

catapp.py

defbool_from_str(s):

ifs.isdigit():

returnint(s)==1

returns.lower()in[yes,true,y]

sed-is/defbool_from_str/defis_affirmative/izk/utils.py

catapp.py

defis_affirmative(s):

ifs.isdigit():

returnint(s)==1

returns.lower()in[yes,true,y]

但是,在定义该文件的文件中重命名了此函数。include的任何其他文件现在bool_from_str也都被替换了。

总结

所有这些工具都打开了无限的可能,可以为我们提取数据并转换其格式,从而有可能构建命令的整个工作流。这些命令中的每一个都具有相对较小的功能(sort排序,cat连接,grep过滤,sed编辑,cut剪切等)。

然后,任何给定的涉及文本的任务都可以简化为一系列较小的任务,每个任务执行一个简单的动作并将其输出传递到下一个任务中。

1
查看完整版本: shell中的文本处理工具虫虫搜奇