精通Linux系列十:如何在4个G的日志中找到错误记录(文件文本操作)

admin 2023-10-14 524 阅读 0评论

文件文本操作

命令含义
grep在文件中查找符合正则表达式的行。
cut从文件中提取列。
paste追加列。
tr将字符翻译成其他字符。
expand,``unexpand在制表符和空格之间转换。
sort按各种标准对文本行进行排序。
uniq在文件中定位相同的行。
tee复制文件在标准输出上同时打印它。

Linux最大的优点就是文本操作:我们通过应用变换,将文本文件(或标准输入)调整到所需的形式,这个操作常常是在管道中进行的。任何读取标准输入和写入标准输出的程序都属于这个范畴,这里我们将介绍一些最重要的工具。

grep

stdin  stdout  - file  -- opt  --help  --version

grep [选项] 模式 [文件]

grep(grep) 命令是Linux工具库中最常用、最强大的工具之一。它的基本理念很简单:给定一个或多个文件,打印出所有符合特定正则表达式模式的行。例如,如果一个文件 randomlines(随机行) 包含以下行:

棕色狐狸快速的跳过去了!
我妈妈刚给我们煎了九个煎饼。
电影在十一点。

如果我们搜索包含“煎饼”的所有行,我们得到:

→ grep pancake randomlines
我妈妈刚给我们煎了九个煎饼。

现在我们用一个正则表达式来匹配以感叹号结尾的行:

→ grep '\!$' randomlines
棕色狐狸快速的跳过去了!

grep(grep) 可以使用两种不同类型的正则表达式,称为 basic(基本) 和 extended(扩展)。基本语法在 Table 2 中。学习正则表达式是非常值得的。很多Linux程序也使用它们,比如 sed(sed) 和 perl(perl)。

有用的选项

-v只打印符合正则表达式的行。
-l只打印包含匹配行的文件的名称,而不是行本身。
-L只打印包含匹配行的文件的名称。
-c只打印匹配行的计数。
-n在每一行匹配的输出前面,打印其原始行号。
-b在每一行匹配的输出前面,打印该行在输入文件中的字节偏移。
-i大小写不敏感匹配。
-w只匹配完整的单词(即,与整个正则表达式匹配的单词)。
-x只匹配完整的行(即,与整个正则表达式匹配的行)。覆盖 -w
-A N在每个匹配行后,打印其文件中的下一个 N 行。
-B N在每个匹配行前,打印其文件中的前一个 N 行。
-C N与 -A N -B N 相同:打印每个匹配行上方  下方的 N 行(来自原始文件)。
--color=always用颜色突出显示匹配的文本,以提高可读性。
-r递归搜索目录及其子目录中的所有文件。
-E使用扩展正则表达式。参见 egrep(egrep)。
-F使用固定字符串列表而非正则表达式。参见 fgrep(fgrep)。

egrep

stdin  stdout  - file  -- opt  --help  --version

egrep [选项] 模式 [文件]

egrep(egrep) 命令就像 grep(grep),但是使用不同的(“扩展的”)语言进行正则表达式。它与 grep -E 是相同的。

表达式含义
.任意单一字符。
[...]匹配此列表中的任意单一字符。
[^...]匹配此列表中不存在的任意单一字符。
(...)分组。
|`
^行首。
$行尾。
\<单词的开始。
\>单词的结束。
[:alnum:]任何字母数字字符。
[:alpha:]任何字母字符。
[:cntrl:]任何控制字符。
[:digit:]任何数字。
[:graph:]任何图形字符。
[:lower:]任何小写字母。
[:print:]任何可打印字符。
[:punct:]任何标点符号。
[:space:]任何空格字符。
[:upper:]任何大写字母。
[:xdigit:]任何十六进制数字。
*一个或多个重复的正则表达式。
\++ 正则表达式重复一次或多次。
\?? 正则表达式出现零次或一次。
\{n \}{n } 正则表达式重复*n*次。
\{ n ,\}{n ,} 正则表达式重复*n*次或更多次。
\{ n , m \}{ n , m } 正则表达式重复次数在*nm(含)之间,n< *m*。
\c字符*c的字面值,即使c是特殊的正则表达式字符。例如,使用 * 来匹配星号或者 \ 来匹配反斜杠。或者,将字面字符放在方括号中,比如 [] 或 []。

GREP 和行结束字符

当你使用 grep(grep) 匹配行尾($)时,如果文本文件是在Microsoft Windows或Mac OS X系统上创建的,可能会出现奇怪的结果。每个操作系统对行结束的标准都不同。在Linux上,文本文件中的每一行都以一个换行符结束(ASCII 10)。在Windows上,文本行以回车(ASCII 13)结束,后面跟着一个换行符。而在OS X上,一个文本文件可能只用换行符或回车符结束每一行。如果 grep 不能正确匹配行尾,可以使用 cat -v 检查非Linux的行尾字符,它会将回车符显示为 ^M

→ cat -v dosfile.
哎呀!这个文件似乎在每行的结尾处使用了^M
在换行符之前有回车符。^M

要删除回车符,可以使用 tr -d 命令:

→ tr -d '\r' < dosfile. > linuxfile.
→ cat -v linuxfile.
哎呀!这个文件似乎在每行的结尾处使用了
在换行符之前有回车符。

fgrep

stdin  stdout  - file  -- opt  --help  --version

fgrep [选项] [固定字符串] [文件]

fgrep(fgrep) 命令就像 grep(grep),但是它接受的是由换行符分隔的固定字符串列表,而不是正则表达式。它与 grep -F 是相同的。例如,如果你有一个每行都是字符串的字典文件:

→ cat my_dictionary_file
aardvark
aback
abandon
...

你可以方便地在一组输入文件中搜索这些字符串:

→ fgrep -f my_dictionary_file story
a little aardvark who went to
visit the abbot at the abbey.

通常,你会使用小写的 -f 选项让 fgrep 从文件中读取固定字符串。你也可以使用引号在命令行中读取固定字符串,但这有点复杂。要在文件中搜索字符串“one”、“two”和“three”,你需要输入:

→ fgrep 'one       注意我们在输入换行符
two
three' myfile

当搜索*和{等非字母数字字符时,fgrep 很方便,因为它们会被当作字面值,而不是正则表达式字符。

cut

stdin  stdout  - file  -- opt  --help  --version

cut -(b|c|f)range [选项] [文件]

cut(cut) 命令从文件中提取文本的列。“列”是由字符偏移定义的(例如,每行的第19个字符):

→ cut -c19 myfile

或者由字节偏移定义(如果你的语言有多字节字符,那么字节和字符是不同的):

→ cut -b19 myfile

或者由分隔字段定义(例如,在一个逗号分隔的文件data.csv中的每一行的第五个字段):

→ cat data.csv
one,two,three,four,five,six,seven
ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN
1,2,3,4,5,6,7
→ cut -f5 -d, data.csv
five
FIVE
5

你不仅限于输出一个单列:你可以给出范围(3-16),逗号分隔序列(3,4,5,6,8,16)或两者都有(3,4,8-16)。对于范围,如果你省略了第一个数字(-16),则默认为1(1-16);如果你省略了最后一个数字(5-),则默认到行尾。

有用的选项

-d C使用字符 C 作为 -f 选项之间的 输入 分隔符,默认为制表符。
--output-delimiter=C使用字符 C 作为 -f 选项之间的 输出 分隔符,默认为制表符。
-s抑制(不打印)不包含分隔符的行。

paste

stdin  stdout  - 文件  -- 选项  --help  --version

paste [选项] [文件]

paste命令与cut命令恰好相反:它将多个文件视为垂直列并在标准输出中合并它们:

→ cat letters
A
B
C
→ cat numbers
1
2
3
4
5
→ paste numbers letters
1  A
2  B
3  C
4
5
→ paste letters numbers
A  1
B  2
C  3
   4
   5

有用的选项

-d delimiters在列之间使用给定的 delimiters 字符;默认为制表符。提供一个字符(-d:)总是使用,或者一个字符列表(-dxyz)在每一行上按顺序应用(第一个分隔符是x,然后是y,然后是z,然后是x,然后是y,...)。
-s横向:转置输出的行和列:→ **paste -s letters numbers** A   B   C 1   2   3   4   5

tr

stdin  stdout  - 文件  -- 选项  --help  --version

tr [选项] charset1 [charset2]

tr命令执行一些简单的、有用的字符集转换。例如,要把文件中的所有内容大写:

→ cat wonderfulfile
This is a very wonderful file.
→ cat wonderfulfile | tr 'a-z' 'A-Z'
THIS IS A VERY WONDERFUL FILE.

或者把所有元音改为星号:

→ cat wonderfulfile | tr aeiouAEIOU '*'
Th*s *s * v*ry w*nd*rf*l f*l*.

或者删除所有元音:

→ cat wonderfulfile | tr -d aeiouAEIOU
Ths s  vry wndrfl fl.

作为一个实际的例子,从DOS文本文件中删除所有回车符,使其与grep等Linux文本工具更兼容:

→ tr -d '\r' < dosfile. > linuxfile.

tr将 charset1 中的第一个字符转换为 charset2 中的第一个字符,第二个转换为第二个,第三个转换为第三个,依此类推。如果 charset1 的长度为 *N*,则只使用 charset2 中的前 N 个字符。(如果 charset1 比 charset2 长,请参阅 -t 选项。)

字符集可以有以下形式:

形式含义
ABDG字符A、B、D、G的序列。
A-Z从A到Z的字符范围。
[x*y]字符 x 的 y 重复。
[: class :]grep接受的字符类([:alnum:][:digit:]等)。

tr还理解printf接受的转义字符“\a”(^G = 响铃警告),“\b”(^H = 退格),“\f”(^L = 换页),“\n”(^J = 新行),“\r”(^M = 返回),“\t”(^I = 制表符),以及“\v”(^K = 垂直制表符),以及符号*nnn*表示八进制值为 nnn 的字符。

tr适用于快速简单的翻译,但对于更强大的任务,请考虑使用sedawkperl

有用的选项

-d从输入中删除 charset1 中的字符。
-s从输入中删除 charset1 中找到的相邻重复项。例如,tr -s aeiouAEIOU 会将相邻的重复元音压缩为单个元音(reeeeeeally 会变成 really)。
-c补码:对 charset1 中未找到的所有字符进行操作。
-t如果 charset1 比 charset2 长,通过截短 charset1 使它们长度相同。如果没有 -t,则 charset2 的最后一个字符(看不见的)会重复,直到 charset2 与 charset1 的长度相同。

expand

stdin  stdout  - file  -- opt  --help  --version

expand [options] [files]
unexpand [options] [files]

expand(展开)命令将制表符转换为看起来等效的空格字符数量,unexpand(取消展开)则执行相反的操作。默认情况下,每八个空格处就有一个制表位,但你可以通过选项更改这个设置。这两个程序默认都写入标准输出。

→ expand tabfile > spacefile
→ expand spacefile > tabfile

要检查文件中是否包含空格或制表符,使用 cat -T 命令,它将制表符显示为 ^I,或者 od -c 命令,它将制表符显示为 \t

Useful options

-t N指定每 N 个空格就有一个制表位。

sort

stdin  stdout  - file  -- opt  --help  --version

sort [options] [files]

sort(排序)命令按照字母顺序或者你指定的其他规则打印文本行。所有提供的文件都被连接起来,然后对结果进行排序并打印:

→ cat threeletters
def
xyz
abc
→ sort threeletters
abc
def
xyz

Useful options

-f忽略大小写排序。
-n数字排序(例如,9在10之前),而不是字母排序(10在9之前,因为它以“1”开头)。
-g另一种数字排序方法,使用不同的算法,该算法在其他方面认识到科学记数法(7.4e3表示“7.4乘以10的三次方”,即7400)。运行 info sort 以获取完整的技术细节。
-u唯一排序:忽略重复行。(如果与 -c 一起用于检查已排序的文件,如果有任何连续的行是相同的,就会失败。)
-c不排序,只检查输入是否已经排序。如果是,什么也不打印;否则,打印一个错误消息。
-b忽略行的开头空格。
-r反转输出:从大到小排序。
-t X将 X 用作 -k 选项的字段分隔符。
-k key选择排序键。(与 -t 结合使用,选择键之间的分隔符字符。)

排序键表示在排序时要考虑的行的一部分,而不是整行。一个例子可能是每行的第五个字符。通常,sort 会认为这些行是排序的:

aaaaz
bbbby

但是如果你的排序键是“每行的第五个字符”,表示为 -k1.5,那么行会被反转,因为 y 在 z 之前。更实用的例子包括这个包含姓名和地址的文件:

→ cat people
George Washington,123 Main Street,New York
Abraham Lincoln,54 First Avenue,San Francisco
John Adams,39 Tremont Street,Boston

一个普通的排序会首先显示“Abraham Lincoln”这行。但是如果你把每行看作三个逗号分隔的值,你可以用以下命令按第二个值进行排序:

→ sort -k2 -t, people
George Washington,123 Main Street,New York
John Adams,39 Tremont Street,Boston
Abraham Lincoln,54 First Avenue,San Francisco

其中,“123 Main Street”在字母上是第一位。同样,你可以按城市(第三个值)进行排序:

→ sort -k3 -t, people
John Adams,39 Tremont Street,Boston
George Washington,123 Main Street,New York
Abraham Lincoln,54 First Avenue,San Francisco

项目意义默认值
F1起始字段必须提供
C1起始字段1内的起始位置1
F2结束字段最后一个字段
C2结束字段内的起始位置1

因此,sort -k1.5基于第一个字段进行排序,从第五个字符开始;而sort -k2.8,5意味着“从第二个字段的第八个字符开始,到第五个字段的第一个字符结束。”-t选项改变了-k的行为,所以它会考虑到像逗号这样的分隔符字符,而不是空格。

你可以重复-k选项来定义多个键,这些键将按照命令行中找到的顺序从第一个到最后一个应用。

uniq

stdin  stdout  - file  -- opt  --help  --version

uniq [options] [files]

uniq(唯一)命令对文本的连续重复行进行操作。例如,如果你有一个文件 myfile

→ cat letters2
a
b
b
c
b

那么uniq会检测并处理两个连续的b,但不会处理第三个b:

→ uniq letters2
a
b
c
b

uniq经常在对文件进行排序后使用:

→ sort letters2 | uniq
a
b
c

在这种情况下,只剩下一个b,因为所有三个b都通过sort变成了相邻的,然后通过uniq压缩成一个。另外,你也可以统计重复行的数量,而不是消除它们:

→ sort letters2 | uniq -c
      1 a
      3 b
      1 c

有用的选项

-c计数相邻重复行。
-i大小写不敏感的操作。
-u只打印唯一的行。
-d只打印重复的行。
-s N在检测重复时,跳过每行的前*N*个字符。
-f N在检测重复时,忽略每行前*N*个以空格分隔的字段。
-w N在检测重复时,只考虑每行的前*N个字符。如果与-s-f一起使用,sort将首先忽略指定数量的字符或字段,然后考虑接下来的N*个字符。

tee

stdin  stdout  - file  -- opt  --help  --version

tee [options] files

cat命令一样,tee(茶)命令将标准输入复制到标准输出,不进行任何更改。同时,它也将相同的标准输入复制到一个或多个文件。tee通常出现在管道的中间,将一些中间数据写入文件,同时也将其传递给管道中的下一个命令:

→ who | tee original_who | sort
barrett   pts/1    Sep 22 21:15
byrnes    pts/0    Sep 15 13:51
silver       :0    Sep 23 20:44
silver    pts/2    Sep 22 21:18

这个命令行在屏幕上产生who的排序输出,但同时也将who的原始,未排序的输出写入到文件 original_who

→ cat original_who
silver       :0    Sep 23 20:44
byrnes    pts/0    Sep 15 13:51
barrett   pts/1    Sep 22 21:15
silver    pts/2    Sep 22 21:18

然后将同样的输出传递到管道的其余部分(sort),在屏幕上产生排序的输出。

有用的选项

-a附加,而不是覆盖文件。
-i忽略中断信号。

更强大的操作

我们仅仅接触了Linux文本过滤的冰山一角。Linux拥有数百种过滤器,能够实现对数据的更复杂的处理。但是,强大的功能往往意味着陡峭的学习曲线,这对于一篇文章来说太多了。以下是一些可以帮助你入门的过滤器。

awk

AWK是一种基于模式匹配的语言。它通过正则表达式匹配数据,然后根据数据执行操作。以下是一些处理文本文件myfile的简单示例。

打印每行的第二个和第四个单词:

→ awk '{print $2, $4}' myfile

打印所有字符数少于60个的行:

→ awk 'length < 60 {print}' myfile

sed

就像AWK一样,sed也是一个模式匹配引擎,可以对文本行进行操作。它的语法与vim和行编辑器ed密切相关。以下是一些简单的示例。

打印文件,将所有出现的字符串“me”更改为“YOU”:

→ sed 's/me/YOU/g' myfile

打印文件,去掉前10行:

→ sed '1,10d' myfile

m4

m4是一种宏处理语言和命令。它在文件中查找关键字,并为它们替换值。例如,给定此文件:

→ cat substitutions
My name is NAME and I am AGE years old.
ifelse(QUOTE,yes,Learn Linux today!)

看看m4如何对NAMEAGEQUOTE进行替换:

→ m4 -DNAME=Sandy substitutions
My name is Sandy and I am AGE years old.
→ m4 -DNAME=Sandy -DAGE=25 substitutions
My name is Sandy and I am 25 years old.

→ m4 -DNAME=Sandy -DAGE=25 -DQUOTE=yes substitutions
My name is Sandy and I am 25 years old.
Learn Linux today!

发表评论

快捷回复: 表情:
aoman baiyan bishi bizui cahan ciya dabing daku deyi doge fadai fanu fendou ganga guzhang haixiu hanxiao zuohengheng zhuakuang zhouma zhemo zhayanjian zaijian yun youhengheng yiwen yinxian xu xieyanxiao xiaoku xiaojiujie xia wunai wozuimei weixiao weiqu tuosai tu touxiao tiaopi shui se saorao qiudale qinqin qiaoda piezui penxue nanguo liulei liuhan lenghan leiben kun kuaikule ku koubi kelian keai jingya jingxi jingkong jie huaixiao haqian aini OK qiang quantou shengli woshou gouyin baoquan aixin bangbangtang xiaoyanger xigua hexie pijiu lanqiu juhua hecai haobang caidao baojin chi dan kulou shuai shouqiang yangtuo youling
提交
评论列表 (有 0 条评论, 524人围观)

最近发表

热门文章

最新留言

热门推荐

标签列表