在 Linux 中,文本处理无非是对文本内容做查看、修改等操作。本章将介绍Linux中常用的文本处理命令,以及被称为Linux三剑客的 grep、sed 和 awk 命令。

有读者可能会问,处理文本内容,用 Vim 编辑器不是很好吗?Vim 允许我们使用键盘、鼠标来对文本内容进行交互性地修改,但在某些场景中,我们可能需要实现对文本内容做自动化的处理,而不是手工处理。

因此,了解一些常用的 Linux 文本处理命令是非常有必要的。

之前有几篇文章讲解了一些文件处理相关的命令,文章链接如下:

【每天一个 Linux 命令】Linux命令 mkdir,cat,touch,vi/vim

【每天一个 Linux 命令】文件目录操作命令大全

下面我们继续深入文件文本处理。

Linux重定向(输入输出重定向)详解

我们知道,Linux 中标准的输入设备默认指的是键盘,标准的输出设备默认指的是显示器。而本节所要介绍的输入、输出重定向,完全可以从字面意思去理解,也就是:

  • 输入重定向:指的是重新指定设备来代替键盘作为新的输入设备;
  • 输出重定向:指的是重新指定设备来代替显示器作为新的输出设备。

通常是用文件或命令的执行结果来代替键盘作为新的输入设备,而新的输出设备通常指的就是文件。

Linux输入重定向

对于输入重定向来说,其需要用到的符号以及作用如表 1 所示。

命令符号格式作用
命令 < 文件将指定文件作为命令的输入设备
命令 << 分界符表示从标准输入设备(键盘)中读入,直到遇到分界符才停止(读入的数据不包括分界符),这里的分界符其实就是自定义的字符串
命令 < 文件 1 > 文件 2将文件 1 作为命令的输入设备,该命令的执行结果输出到文件 2 中。

【例 1】
默认情况下,cat 命令会接受标准输入设备(键盘)的输入,并显示到控制台,但如果用文件代替键盘作为输入设备,那么该命令会以指定的文件作为输入设备,并将文件中的内容读取并显示到控制台。

以 /etc/passwd 文件(存储了系统中所有用户的基本信息)为例,执行如下命令:

[root@localhost ~]# cat /etc/passwd
\#这里省略输出信息,读者可自行查看
[root@localhost ~]# cat < /etc/passwd
\#输出结果同上面命令相同

注意,虽然执行结果相同,但第一行代表是以键盘作为输入设备,而第二行代码是以 /etc/passwd 文件作为输入设备。

【例 2】

[root@localhost ~]# cat << 0
>c.biancheng.net
>Linux
>0
c.biancheng.net
Linux

可以看到,当指定了 0 作为分界符之后,只要不输入 0,就可以一直输入数据。

【例 3】
首先,新建文本文件 a.tx,然后执行如下命令:

[root@localhost ~]# cat a.txt
[root@localhost ~]# cat < /etc/passwd > a.txt
[root@localhost ~]# cat a.txt
\#输出了和 /etc/passwd 文件内容相同的数据

可以看到,通过重定向 /etc/passwd 作为输入设备,并输出重定向到 a.txt,最终实现了将 /etc/passwd 文件中内容复制到 a.txt 中。

Linux输出重定向

相较于输入重定向,我们使用输出重定向的频率更高。并且,和输入重定向不同的是,输出重定向还可以细分为标准输出重定向和错误输出重定向两种技术。

例如,使用 ls 命令分别查看两个文件的属性信息,但其中一个文件是不存在的,如下所示:

[root@localhost ~]# touch demo1.txt
[root@localhost ~]# ls -l demo1.txt
-rw-rw-r--. 1 root root 0 Oct 12 15:02 demo1.txt
[root@localhost ~]# ls -l demo2.txt  <-- 不存在的文件
ls: cannot access demo2.txt: No such file or directory

上述命令中,demo1.txt 是存在的,因此正确输出了该文件的一些属性信息,这也是该命令执行的标准输出信息;而 demo2.txt 是不存在的,因此执行 ls 命令之后显示的报错信息,是该命令的错误输出信息。

再次强调,要想把原本输出到屏幕上的数据转而写入到文件中,这两种输出信息就要区别对待。

在此基础上,标准输出重定向和错误输出重定向又分别包含清空写入和追加写入两种模式。因此,对于输出重定向来说,其需要用到的符号以及作用如表 2 所示。

命令符号格式作用
命令 > 文件将命令执行的标准输出结果重定向输出到指定的文件中,如果该文件已包含数据,会清空原有数据,再写入新数据。
命令 2> 文件将命令执行的错误输出结果重定向到指定的文件中,如果该文件中已包含数据,会清空原有数据,再写入新数据。
命令 >> 文件将命令执行的标准输出结果重定向输出到指定的文件中,如果该文件已包含数据,新数据将写入到原有内容的后面。
命令 2>> 文件将命令执行的错误输出结果重定向到指定的文件中,如果该文件中已包含数据,新数据将写入到原有内容的后面。
命令 >> 文件 2>&1 或者 命令 &>> 文件将标准输出或者错误输出写入到指定文件,如果该文件中已包含数据,新数据将写入到原有内容的后面。注意,第一种格式中,最后的 2>&1 是一体的,可以认为是固定写法。

【例 4】新建一个包含有 “Linux” 字符串的文本文件 Linux.txt,以及空文本文件 demo.txt,然后执行如下命令:

[root@localhost ~]# cat Linux.txt > demo.txt
[root@localhost ~]# cat demo.txt
Linux
[root@localhost ~]# cat Linux.txt > demo.txt
[root@localhost ~]# cat demo.txt
Linux   <--这里的 Linux 是清空原有的 Linux 之后,写入的新的 Linux
[root@localhost ~]# cat Linux.txt >> demo.txt
[root@localhost ~]# cat demo.txt
Linux
Linux   <--以追加的方式,新数据写入到原有数据之后
[root@localhost ~]# cat b.txt > demo.txt
cat: b.txt: No such file or directory <-- 错误输出信息依然输出到了显示器中
[root@localhost ~]# cat b.txt 2> demo.txt
[root@localhost ~]# cat demo.txt
cat: b.txt: No such file or directory <--清空文件,再将错误输出信息写入到该文件中
[root@localhost ~]# cat b.txt 2>> demo.txt
[root@localhost ~]# cat demo.txt
cat: b.txt: No such file or directory
cat: b.txt: No such file or directory <--追加写入错误输出信息

Linux grep命令详解:查找文件内容

很多时候,我们并不需要列出文件的全部内容,而是从文件中找到包含指定信息的那些行,要实现这个目的,可以使用 grep 命令。

grep 命令作为 Linux 文本处理三剑客的一员,另外两个是 sed 和 awk,它们会在后续章节中作详细介绍。

grep 命令的由来可以追溯到 UNIX 诞生的早期,在 UNIX 系统中,搜索的模式(patterns)被称为正则表达式(regular expressions),为了要彻底搜索一个文件,有的用户在要搜索的字符串前加上前缀 global(全面的),一旦找到相匹配的内容,用户就像将其输出(print)到屏幕上,而将这一系列的操作整合到一起就是 global regular expressions print,而这也就是 grep 命令的全称。

grep命令能够在一个或多个文件中,搜索某一特定的字符模式(也就是正则表达式),此模式可以是单一的字符、字符串、单词或句子。

正则表达式是描述一组字符串的一个模式,正则表达式的构成模仿了数学表达式,通过使用操作符将较小的表达式组合成一个新的表达式。正则表达式可以是一些纯文本文字,也可以是用来产生模式的一些特殊字符。为了进一步定义一个搜索模式,grep 命令支持如表 1 所示的这几种正则表达式的元字符(也就是通配符)。

通配符功能
c*将匹配 0 个(即空白)或多个字符 c(c 为任一字符)。
.将匹配任何一个字符,且只能是一个字符。
[xyz]匹配方括号中的任意一个字符。
[^xyz]匹配除方括号中字符外的所有字符。
^锁定行的开头。
$锁定行的结尾。

需要注意的是,在基本正则表达式中,如通配符 *、+、{、|、( 和 )等,已经失去了它们原本的含义,而若要恢复它们原本的含义,则要在之前添加反斜杠 \,如 *、+、{、|、( 和 )。

grep 命令是用来在每一个文件或中(或特定输出上)搜索特定的模式,当使用 grep 时,包含指定字符模式的每一行内容,都会被打印(显示)到屏幕上,但是使用 grep 命令并不改变文件中的内容。

grep 命令的基本格式如下:

[root@localhost ~]# grep [选项] 模式 文件名

这里的模式,要么是字符(串),要么是正则表达式。而此命令常用的选项以及各自的含义如表 2 所示。

选项含义
-c仅列出文件中包含模式的行数。
-i忽略模式中的字母大小写。
-l列出带有匹配行的文件名。
-n在每一行的最前面列出行号。
-v列出没有匹配模式的行。
-w把表达式当做一个完整的单字符来搜寻,忽略那些部分匹配的行。

注意,如果是搜索多个文件,grep 命令的搜索结果只显示文件中发现匹配模式的文件名;而如果搜索单个文件,grep 命令的结果将显示每一个包含匹配模式的行。

【例 1】假设有一份 emp.data 员工清单,现在要搜索此文件,找出职位为 CLERK 的所有员工,则执行命令如下:

[root@localhost ~]# grep CLERK emp.data
#忽略输出内容

而在此基础上,如果只想知道职位为 CLERK 的员工的人数,可以使用“-c”选项,执行命令如下:

[root@localhost ~]# grep -c CLERK emp.data
#忽略输出内容

【例 2】搜索 emp.data 文件,使用正则表达式找出以 78 开头的数据行,执行命令如下:

[root@localhost ~]# grep ^78 emp.data
#忽略输出内容

grep 命令的功能非常强大,通过利用它的不同选项以及变化万千的正则表达式,可以获取任何我们所需要的信息。本节所介绍的 grep 命令,只介绍了它的一部分基础知识,比如说,grep 命令可用的选项还有很多,且用法也五花八门,不过对于初学者来说,本节所介绍的内容已经足以应付多数 Linux 系统的日常工作了。

正则表达式

2.1 认识正则

(1)介绍

正则表达式应用广泛,在绝大多数的编程语言都可以完美应用,在Linux中,也有着极大的用处。

使用正则表达式,可以有效的筛选出需要的文本,然后结合相应的支持的工具或语言,完成任务需求。

在本篇博客中,我们使用grep/egrep来完成对正则表达式的调用

(2)正则表达式类型

正则表达式可以使用正则表达式引擎实现,正则表达式引擎是解释正则表达式模式并使用这些模式匹配文本的基础软件。

在Linux中,常用的正则表达式有:

  • POSIX 基本正则表达式(BRE)引擎
  • POSIX 扩展正则表达式(BRE)引擎

2.2 基本正则表达式

2.2.1 匹配字符

(1)格式

  • . 匹配任意单个字符,不能匹配空行
  • [] 匹配指定范围内的任意单个字符
  • [^] 取反
  • [:alnum:] 或 [0-9a-zA-Z]
  • [:alpha:] 或 [a-zA-Z]
  • [:upper:] 或 [A-Z]
  • [:lower:] 或 [a-z]
  • [:blank:] 空白字符(空格和制表符)
  • [:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
  • [:cntrl:] 不可打印的控制字符(退格、删除、警铃…)
  • [:digit:] 十进制数字 或[0-9]
  • [:xdigit:]十六进制数字
  • [:graph:] 可打印的非空白字符
  • [:print:] 可打印字符
  • [:punct:] 标点符号

(2)演示

img

2.2.2 配置次数

(1)格式

  • ***** 匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
  • .* 任意长度的任意字符,不包括0次
  • ? 匹配其前面的字符0 或 1次
  • + 匹配其前面的字符至少1次
  • {n} 匹配前面的字符n次
  • {m,n} 匹配前面的字符至少m 次,至多n次
  • {,n} 匹配前面的字符至多n次
  • {n,} 匹配前面的字符至少n次

(2)演示

img

2.2.3 位置锚定:定位出现的位置

(1)格式

  • ^ 行首锚定,用于模式的最左侧
  • $ 行尾锚定,用于模式的最右侧
  • ^PATTERN$,用于模式匹配整行
  • ^$ 空行
  • 1.*$ 空白行
  • < 或 \b 词首锚定,用于单词模式的左侧
  • > 或 \b 词尾锚定;用于单词模式的右侧
  • <PATTERN>

(2)演示

img

2.2.4 分组和后向引用

(1)格式

① 分组:() 将一个或多个字符捆绑在一起,当作一个整体进行处理

分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, …

② 后向引用

引用前面的分组括号中的模式所匹配字符,而非模式本身

1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符

2 表示从左侧起第2个左括号以及与之匹配右括号之间的模式所匹配到的字符,以此类推

& 表示前面的分组中所有字符

③ 流程分析如下:

img

(2)演示

img

2.3 扩展正则表达式

(1)字符匹配:

  • . 任意单个字符
  • [] 指定范围的字符
  • [^] 不在指定范围的字符
  • 次数匹配:
  • * :匹配前面字符任意次
  • ? : 0 或1次
  • + :1 次或多次
  • {m} :匹配m次 次
  • {m,n} :至少m ,至多n次

(2)位置锚定:

  • ^ : 行首
  • $ : 行尾
  • <, \b : 语首
  • >, \b : 语尾
  • 分组:()
  • 后向引用:\1, \2, …

(3)总结

除了<, \b : 语首、>, \b : 语尾;使用其他正则都可以去掉\;上面有演示案例,不在进行演示


  1. [:space:] ↩︎

Logo

更多推荐