字符处理
管道
说起“管道”,很容易让人想起现实生活中使用的水管、输气管等,它们的作用在于运输气体或液体等物质,有了管道,会让我们方便很多。
在 Linux 中也存在着管道,它是一个固定大小的缓冲区,该缓冲区的大小为 1 页,即 4K 字节。
管道是一种使用非常频繁的通信机制,我们可以用管道符“|
”来连接进程,由管道连接起来的进程可以自动运行,如同有一个数据流一样,所以管道表现为输入输出重定向的一种方法,它可以把一个命令的输出内容当作下一个命令的输入内容,两个命令之间只需要使用管道符连接即可。
举个例子,如果想要看一下/etc/init.d
目录下文件的详细信息,可以使用ls -l /etc/init.d
命令,不过这可能会出现因输出内容过多而造成翻屏的情况,这样一来,先输出的内容在屏幕上就看不到了。
其实这里就可以利用管道功能,将命令的输出使用 more 程序一页一页地显示出来
1 |
|
可以看出,通过管道,使ls -l /etc/init.d
命令输出的内容作为下一个命令more
的输入,这样就可以方便地查看输出内容了。
使用 grep 搜索文本
grep 是 Linux 下非常强大的基于行的文本搜索工具,使用该工具时,如果匹配到相关信息就会打印出符合条件的所有行。
下面列出了该命令常用的参数:
1 2 3 4 5 |
|
为演示 grep 的用法,这里首先创建一个文件,文件名和文件内容如下:
1 2 3 4 |
|
下面要找出含有 name 的行:
1 2 |
|
打印出含有 name 的行的行编号:
1 2 |
|
由于 grep 区分大小写,所以虽然第二行中含有大写的 NAME,但是也不会匹配到。
如果希望忽略大小写,可以加上 -i 参数。
1 2 3 |
|
如果想知道文件中一共有多少包含 name 的行,可以使用下面的命令。
注意到第二条命令和第一条命令只有一个参数的差别,但是输出的结果却是不一样的。
1 2 3 4 |
|
如果想打印出文件中不包含 name 的行,可以使用 grep 的反选参数 -v。
1 2 3 4 5 |
|
以上命令都可以使用 cat 命令 + 管道符改写。比如上一个命令可以这样改写:
1 2 |
|
使用 sort 排序
很多情况下需要对无序的数据进行排序,这时就要用到 sort 排序了。
下面列出了该命令常用的参数:
1 2 3 4 5 |
|
为演示 sort 的用法,这里首先创建一个文件,文件名和文件内容如下:
1 2 3 4 5 6 |
|
下面对内容进行排序:
1 2 3 4 5 6 7 |
|
直接排序时,默认按照每行的第一个字符进行排序,下面表示对输出内容进行反向排序:
1 2 3 4 5 6 7 |
|
可观察到,sort.txt 文件具有一个特点,第一个字符是字母,第三个字符是数字,中间用冒号隔开。
这样就可以用 -t 指定分隔符,并用 -k 指定用于排序的列了。
1 2 3 4 5 6 7 |
|
在上面的命令中,当前的排序是按照以冒号隔开的第二部分进行的,不过第二行是f:11
,这一行不应该在最后一行吗?
因为 11 是最大的。但其实命令的输出并不是错误的,因为按照排序的方式,只会看第一个字符,而 11 第一个字符是 1,按照字符来排序那它确实比 2 小。
如果想要指定按照“数字”的方式进行排序,则需要加上 -n 参数
1 2 3 4 5 6 7 |
|
使用 uniq 删除重复内容
如果文件(或标准输出)中有多行完全相同的内容,我们很自然希望能删除重复的行,同时还可以统计出完全相同的行出现的总次数,uniq 命令就能帮助解决这个问题。下面列出了该命令常用的参数:
1 2 3 |
|
为演示 uniq 的用法,这里首先创建一个文件,文件名和内容如下:
1 2 3 4 5 |
|
需要说明的是,uniq 一般都需要和 sort 命令一起使用,也就是先将文件使用 sort 进行排序(这样重复的内容就能显示在连续的几行中),然后再使用 uniq 删除掉重复的内容(uniq 的作用就在于删除连续的完全一致的行)。
观察一下以下两次命令的输出,第一次直接 cat 输出文件,然后使用 uniq 命令,输出的内容居然和原文件 uniq.txt 的内容是一样的,这是因为 uniq 命令只会对比相邻的行,如果有连续相同的若干行则删除重复内容,仅输出一行。
如果相同的行非连续,则 uniq 命令不具备删除效果。
第二次则在使用 sort 排序后再使用 uniq 命令,这时就达到了预期的效果。
1 2 3 4 5 6 7 8 |
|
使用 -c 参数就会在每行前面打印出该行重复的次数
1 2 3 |
|
使用 cut 截取文本
顾名思义,cut 就是截取的意思,它能处理的对象是“一行”文本,可从中选取出用户所需要的部分。
在有特定的分隔符时,可以指定分隔符,然后打印出以分隔符隔开的具体某一列或某几列,这里 cut 的用法如下:
1 |
|
举个例子,在文件/etc/passwd
中,每行都是使用 6 个冒号隔开的 7 列文本,那么很容易使用 cut 的这个功能来提取出特定的细腻。
比如说我们需要打印出系统中的所有用户:
1 2 3 4 5 6 7 8 9 10 11 |
|
或者想同时打印出用户和这个用户的家目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
如果还想同时打印出每位用户的登录 shell:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
以上 cut 使用的场景是在处理的行中有特定分隔符的时候,但如果要处理的行是没有分隔符的,那是不是 cut 就没有用武之地了?
答案是否定的,cut 还可以打印指定的字符,这时候 cut 的用法如下:
1 |
|
继续使用/etc/passwd
为例子,假设想要打印出每行第 1~5 个字符,以及 7~10 个字符的内容,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
使用 tr 做文本转换
tr 命令比较简单,其主要作用在于文本转换或删除。
这里假设要把文件/etc/passwd
中的小写字母转换为大写字母,然后再尝试删除文本中的冒号,如下所示:
1 2 3 4 5 6 7 8 |
|
使用 paste 做文本合并
paste 的作用在于将文件按照行进行合并,中间使用 tab 隔开。
假设有两个文件分别为 a.txt、b.txt,下面使用 paste 命令来合并文件,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
也可以使用 -d 指定在合并文件时行间的分隔符
1 2 3 4 |
|
使用 split 分割大文件
早些前,“文件分割”这 4 个字还是比较流行的,当时受限制于移动存储设备的限制,大文件的转移往往需要通过分割成小文件分别存储来实现,之后会再使用合并的方式还原成原始文件。
虽然随着现代移动存储、网络存储的发展,分割大文件的做法已经不那么流行了,但是了解以下还是必要的。
在 Linux 下使用 split 命令来实现文件的分割,支持按照行数分割和按照大小分割这两种模式。
要说明的是,二进制文件因为没有“行”的概念,所以二进制文件无法使用行分割,而只能按照文件大小进行分割。
相关命令如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
xargs 命令
xargs 是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。
xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。
xargs 也可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。
xargs 默认的命令是 echo,这意味着通过管道传递给 xargs 的输入将会包含换行和空白,不过通过 xargs 的处理,换行和空白将被空格取代。
xargs 是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令。
之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了 xargs 命令,例如:
1 2 |
|
xargs 一般是和管道一起使用。
1 |
|
批量删除docker镜像为none的方法
docker images | grep none | awk '{print $3}' | xargs docker rmi