1 管道命令(pipe)介绍
众所周知,bash命令执行的时候会输出信息,但有时这些信息必须要经过几次处理之后才能得到我们想要的格式,此时应该如何处置?这就牵涉到 管道命令(pipe) 了。管道命令使用的是|
这个界定符号。另外,管道命令与连续执行命令是不一样的,这点下面我们会说明。
我们先来看一个管道命令的例子。假设我们需要看/etc
目录下有多少文件,那么可以利用ls /etc
来查看,不过由于文件数量太多,导致一口气就将屏幕塞满了,而不知道前面输出的内容是啥:
root@orion-orion:~ ls -al /etc
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
# 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
:不一定会存在,一般代表选择进