Linux:管道命令与文本处理三剑客(grep、sed、awk)

1 管道命令(pipe)介绍
众所周知,bash命令执行的时候会输出信息,但有时这些信息必须要经过几次处理之后才能得到我们想要的格式,此时应该如何处置?这就牵涉到 管道命令(pipe) 了。管道命令使用的是|这个界定符号。另外,管道命令与连续执行命令是不一样的,这点下面我们会说明。

我们先来看一个管道命令的例子。假设我们需要看/etc目录下有多少文件,那么可以利用ls /etc来查看,不过由于文件数量太多,导致一口气就将屏幕塞满了,而不知道前面输出的内容是啥:

root@orion-orion:~ ls -al /etc root@qi
total 944
drwxr-xr-x 1 root root 4096 Feb 19 11:38 .
drwxr-xr-x 1 root root 4096 Nov 23 2021 …
drwxr-xr-x 3 root root 4096 Jun 5 2021 .java

drwxr-xr-x 2 root root 4096 Jul 24 2018 xfce4
此时,我们可以使用less命令的协助:

root@orion-orion:~ ls -al /etc | less
total 944
drwxr-xr-x 1 root root 4096 Feb 19 11:38 .
drwxr-xr-x 1 root root 4096 Nov 23 2021 …
drwxr-xr-x 3 root root 4096 Jun 5 2021 .java
:
如此一来,使用ls命令输出的内容就能够被less读取,并且利用less的功能,我们就能够前后翻动相关的信息了。其中的关键就是这个管道命令|。管道命令|仅能处理前一个命令传来的标准输出信息,而对于标准错误信息并没有直接处理能力。那么整体的管道命令可以使用下图表示:
在这里插入图片描述
在每个管道后面接的第一个数据必定是命令,而且这个命令必须要能够接受标准输出的数据才行,这样的命令才可为管道命令。例如less、grep、sed、awk等都是可以接受标准输入的管道命令,而ls、cp、mv就不是管道命令,因为它们并不会接受来自stdin的数据。总结一下,管道命令主要有两个需要注意的地方:

管道命令仅会处理标准输出,对于标准错误会予以忽略;
管道命令必须要能够接受来自前一个命令的数据成为标准输入继续处理才行(这也是其与连续执行命令之不同)。
如果我们强行让标准错误为管道命令所用,那么可以使用2>&1将标准错误2>重定向到标准输出1>。

接下来我们选取grep、sed、awk这三个用于文本处理的管道命令来进行介绍。这三个命令可谓是Linux下操作文本的三大利器,合称Linux文本处理三剑客。

2 行选取命令grep
grep命令可以一行一行地分析信息,若某行含有我们所需要的信息,则就将该行拿出来。简单的语法如下:

grep [-acinv] [–color=auto] ‘查找字符’ filename
它的选项与参数如下:

-a:将二进制文件以文本文件的方式查找数据。
-c:计算找到’查找字符’的次数。
-i:忽略大小写的不同,所以大小写视为相同。
-n:顺便输出行号。
-v:反向选择,亦即显示出没有’查找字符’内容的那些行。
下面展示几个例子。

范例一:将last当中,有出现root的那一行就显示出来。

root@orion-orion:~ last | grep ‘root’
root pts/2 10.249.252.8 Mon Apr 6 06:08 - 09:02 (02:54)
root pts/1 10.249.252.8 Mon Apr 6 06:05 - 06:08 (00:03)
root pts/1 10.249.252.8 Mon Apr 6 03:13 - 06:05 (02:51)

root pts/1 :1 Tue Jul 24 06:44 - 06:45 (00:00)
root pts/1 172.17.0.1 Tue Apr 10 14:23 - 14:23 (00:00)
root pts/1 127.0.0.1 Tue Apr 10 08:57 - 08:57 (00:00)
这里前3行是我们校内的局域网IP(以10.249打头),172.17.0.1是Docker中默认网桥docker0的IP地址,127.0.0.1为本地回环地址。
范例二:与范例一相反,只要没有root的就取出。

root@orion-orion:~ last | grep -v ‘root’
person pts/1 127.0.0.1 Tue Apr 10 08:54 - 08:54 (00:00)
范例三:在last的输出信息中,只要有root就取出,并且仅取第一栏:

root@orion-orion:~ last | grep “root” | awk ‘{print $1}’
root
root
root

这里用到了我们后面要讲的awk命令,这一命令用于将一行分为多个字段来处理,我们后面将会详细介绍。
范例四:取出/etc/adduser.conf内含UID的那几行,且将找到的关键字部分用特殊颜色显示出来:

root@orion-orion:~ grep --color=auto “UID” /etc/adduser.conf root@qi

FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs

package, may assume that UIDs less than 100 are unallocated.

FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999

FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically

FIRST_UID=1000
LAST_UID=29999
可以看到找到的关键字部分用红色显示(当然这里的代码块看不出来效果,需要在终端进行渲染)。注意,在我的Ubuntu 18.04系统中默认的grep已经主动使用–color=auto选项在alias中了,因此不用手动加–color=auto也会标红(事实上,在我本地的Mac系统中也是如此)。

3 行操作命令sed
前面我们说过,grep命令可以解析一行文字,若该行含有某关键词就会将其整行列出来。接下来我们要讲的sed命令也是一个管道命令(可以分析标准输入),它还可以对特定行进行新增、删除、替换等。sed的用法如下:

sed [-nefr] [操作]
它的选项与参数如下:

-n:使用安静(silent)模式。在一般的sed用法中,所有来自stdin的数据一般都会被列出到屏幕上,但如果加上-n参数后,则只有经过sed选择的那些行才会被列出来。
-e:使sed的操作结果由屏幕输出,而改变原有文件(默认已选该参数, 与-i的直接修改文件相反)。
-f:从一个文件内读取将要执行的sed操作,-f filename可以执行filename中写好的sed操作。
-r:sed的操作使用的是扩展型正则表达式的语法(默认是基础正则表达式语法)。
-i:直接修改读取的文件内容,而不是由屏幕输出。
关于其中的[操作]部分,其格式如下:

[n1[,n2]]function
n1, n2:不一定会存在,一般代表选择进行操作的行数,比如我的操作需要在10到20行之间进行,则写为10, 20[操作名称]。

具体地,对行的操作函数function包括下面这些东西:

a:新增,a的后面可以接字符,这些字符将被添加在n1/n2的下一行;
c:替换,c的后面可以接字符,这些字符可以替换n1,n2之间的行;
d:删除,因为是删除,所以d后面通常不需要接任何东西;
i:插入,i的后面可以接字符,这些字符将被添加在n1/n2的上一行;
p:打印,亦即将某些选择的行打印出来。通常p会与参数sed -n一起运行。
s:替换,可以直接进行替换的工作,通常这个s的操作可以搭配正则表达式。
下面我们来举几个例子进行说明。

以行为单位的新增/删除功能

范例一:查看/etc/passwd文件的内容并且在每一行前面加上行号,同时将2-5行删除。

root@orion-orion:~ cat -n /etc/passwd | sed ‘2,5d’
1 root❌0:0:root:/root:/bin/zsh
6 games❌5:60:games:/usr/games:/usr/sbin/nologin
7 man❌6:12👨/var/cache/man:/usr/sbin/nologin
8 lp❌7:7:lp:/var/spool/lpd:/usr/sbin/nologin

可以看到sed的操作为2,5d,也即删除25行,所以显示的数据就没有25行。此外,请注意原本应该是要执行sed -e才对,不过这里没有-e也行,因为已经默认选了。同时也要注意sed后面接的操作务必以两个单引号’'括住。

我们将范例变一下,如果要删除第2行,那么可以使用cat -n /etc/passwd | sed ‘2d’ ;如果是要删除第3到最后一行,则是cat -n /etc/passwd | sed '3, d ′ ,这里美元符号 d',这里美元符号 d,这里美元符号代表最后一行。

范例二: 承接上题,在第2行后(亦即是第3行)加上drink tea字样。

root@orion-orion:~ cat -n /etc/passwd | sed ‘2a Drink tea?’
1 root❌0:0:root:/root:/bin/zsh
2 daemon❌1:1:daemon:/usr/sbin:/usr/sbin/nologin
Drink tea?
3 bin❌2:2:bin:/bin:/usr/sbin/nologin

如果想要加在第2行前面,将新增操作改为插入操作,即cat -n /etc/passwd | sed '2i Drink tea?'就行了。

范例三:继续承接上题,现在我们想要在第2行后面加上两行字,例如Drink tea or…与Drink beer?

root@orion-orion:~ cat -n /etc/passwd | sed ‘2a Drink tea or…\ root@qi
\ Drink beer?’
1 root❌0:0:root:/root:/bin/zsh
2 daemon❌1:1:daemon:/usr/sbin:/usr/sbin/nologin
Drink tea or…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值