摘要本文呢会介绍在 shell 编程中经常使用到的重定向的相关知识,以及文本处理的一些常用命令。本文主要有以下的内容,标准输入输出-stdio(包含三种 i/o 流);管道符的简单使用;重定向(重定向输入,重定向输出,重定向错误);简单的文本处理(「排序」与「合并」)和 xargs 命令。
简介
这篇文章将着重介绍在 shell
编程中经常使用到的重定向的相关知识,以及文本处理的一些常用命令。本文会分为以下几个内容进行介绍:
- 标准输入输出-stdio(包含三种 i/o 流);
- 管道符的简单使用;
- 重定向(重定向输入,重定向输出,重定向错误);
- 简单的文本处理(「排序」与「合并」);
- xargs 命令(将字符串按指定符号进行分割);
标准输入输出-stdio
对于 linux 内核中的标准 i/o
库 stdio
提供了一个高效的缓存 i/o
流接口。一般情况下,每个程序在启动时都会有三个 stream
(流)在启动时被预定义,一个用于输入,一个用于输出,还有一个用于打印诊断或者错误信息。
对于 linux 系统中来说,读取标准输入和打印标准输出的地方默认情况下都是所使用的终端。对应 shell
中常使用的三种标准 i/o 流:
stdin
,标准输入流;stdout
,标准输出流;stderr
,诊断错误信息流;
输入流-stdin
输入流(input stream)被称作标准输入(standard input),缩写形式即为 stdin
。在程序启动时,与 stdin
关联的整数文件描述符为 0
。
这里我们引入文件描述符的概念(百度百科的定义):
- 内核(kernel)利用文件描述符(file descriptor)来访问文件。
- 文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
- 实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。
输出流-stdout
输出流(output stream)被称作标准输出(standard output),缩写形式即为 stdout
。在程序启动时,与 stdout
关联的整数文件描述符为 1
。
错误流-stderr
错误流(error stream)被称作标准错误输出(standard error),缩写形式即为 stderr
。在程序启动时,与 stderr
关联的整数文件描述符为 2
。
linux 管道符
linux 管道来说可以用于 linux 程序之间,linux 命令之间以及 linux 程序和命令之间的通信。 在 shell 中,管道符(pipeline)是 shell
编程中众多控制操作符其中的一个,用来分隔一个或多个命令的序列。shell 编程中管道符号是竖杠符号 |
(但是有时会使用到 |&
符号,这种用法会同时包含「输出流」和「错误流」,该用法将在后面的内容中详细描述)。
在 shell 中使用管道的格式如下,代表着 command1
的标准输出作为 command2
的标准输入使用,而 command2
的标准输出又作为 command3
的标准输入使用:
- command1 | command2 | command3
例如下面一个简单的例子。第一个命令使用 echo
来输出文字,第二个命令使用 grep
将第一个 echo
的输出当作输出:
重定向
在执行命令之前,我们可以使用 shell 解释的特殊符号重定其输入和输出。下面会分别来将「重定向输入」,「重定向输出」,
重定向输入
重定向输入的一般格式如下:
- [n] < file
上面命令代表的意思是将输入从文件描述符为 n
的文件重定向到 file
。不指定 n
时,文件描述符 n
为 0
,为标准输入。代表着将输入从标准输入重定向到 file
中(简单理解为,将文件 file
的内容作为输入)。
我们来看一个例子。首先新建一个文件,在其中写入 happy new year!
。如下所示:
接着将该文件作为 grep
的输入,使用 grep
查找 happy
:
重定向输出
重定向输出的格式如下所示:
- [n] > file
这里代表的意思是将输出从文件描述符为 n
的文件重定向到 file
。不指定 n
时,文件描述符 n
为 1
,为标准输出。代表着将输出从标准输出重定向到 file
中。
这里需要注意的是,如果 file
不存在,将会创建 file
,如果 file
存在,文件大小将被设为 0
,然后输出,即覆盖原有文件的内容。如果需要将输出内容附加到文件中,需要使用 >>
来替代 >
符号。
我们来看一个例子。我们将 echo
的输出保存在文件 file1
中,然后查看文件内容:
重定向 stdout 和 stderr
这里我们会用到管道符部分提到的 |&
符号,使用的格式如下:
- command1 |& command2
上面的命令表示将 command1
命令的「标准输出」和「标准错误」作为 command2
的标准输入。不同于 |
,这里多了一个标准错误的选项。
下面来看一个例子。我们查看当前目录下一个不存在的文件,这个时候会出现「标准错误」。我们使用 |&
符号将这个标准错误作为 cat 的输入,接着将 cat 的输出重定向到 file 文件:
除此之外,还可以使用 &>
符号达到一样的效果。如下所示,将「标准错误」输出到 file 文件中:
更常用的一种用法是将「标准输入」和「标准错误」分别重定向到两个文件。例如 command 2>err.log 1>info.log
这个命令表示 err.log
和 info.log
分别用来存储 command 命令的标准错误和标准输出。下面是一个例子:
简单的文本处理
linux 的一些命令支持对文件进行简单的操作。例如现在有一个文件,存储着个人信息(包含姓名和年龄),如下所示:
- name1 30
- name2 20
- name3 25
对文件进行排序
我们可以使用 sort
命令对文本内容进行排序。关于 sort
命令的详细用法可以使用 sort --help
查看,这里我们简单介绍一些常用的参数。
-u
去除重复行;-t
指定分隔字符,例如上面我们使用的空格字符,默认为空格;-o
输出到指定文件;-k
指定使用某一列进行排序;-r
修改默认的升序排序为降序;
例如我们对上面的文件,按照年龄进行降序排序,最终的结果如下所示:
对文件的合并
有两种文件合并的方式,分别是 paste
和 join
的方式。
paste
命令可以将多个文件以列对列的方式加以合并;join
命令可以将多个文件中有相同特征的列进行合并;
现在我们新建一个文件,里面包含每个学生和他的学号,如下所示:
- name1 man
- name2 woman
- name4 man
我们首先来看一下paste
命令的效果(可以看到只是单纯的合并):
如果这个时候我们使用join
命令,则会尝试进行合并(保留共有内容的行):
xargs 命令
xargs
命令可以从标准输入构建和执行命令。xargs
常用来给其他命令传递参数,从标准输入读取数据,默认情况下使用空格或者换行符作为默认定界符,忽略空白行,并且在没有指定命令的时候,默认将数据传递给 /bin/echo
,即我们常用的 echo
命令作为参数。下面我们将介绍一些常用的参数:
-a
使用该参数指定从文件中读取,而不是标准输入;-d
自定义定界符;-n
每行的最多参数个数;
例如下面的例子中,我们使用 x 作为「定界符」,每行显示一个,将原本一行的内容分开: