Linux探索之旅之流、管道、重定向,三管齐下

jackxiang 2015-9-14 11:53 | |
背景:关于Linux的流概念,比如在调试C代码时,出错了,或是想捕获输出的错误到同一个文件,这些都要用到流知识,输入,输出,错误分别是:0,1,2,于是有了 >2 >2&1,该文章都有详细解答讲解,写的非常好,写的非常好,难得的好干货,拨云见雾………我已经无力吐槽。
如:
[root@iZ25dcp92ckZ multepoolserver]# cat aaa.txt
cat: aaa.txt: 没有那个文件或目录
[root@iZ25dcp92ckZ multepoolserver]# cat aaa.txt > notexist.txt 2>&1
[root@iZ25dcp92ckZ multepoolserver]# cat notexist.txt
cat: aaa.txt: 没有那个文件或目录
————————————————————————————————————
./multepoolser > echoOut.txt
./tianxia > appleOut.txt 2>&1  

————————————————————————————————————————————————————————
内容简介

1、第三部分第二课:流、管道、重定向,三管齐下

2、第三部分第三课预告:监视系统活动,滴水不漏

流、管道、重定向,三管齐下

这一课我们来学一些非常有用的内容,而且相当有意思,而且内容很多,而且有可能颠覆你的三《观》(毕竟三管齐下,不颠覆三观也难)。

今天的标题中的三个名称,听上去就怪怪的。什么流,管道,重定向,都啥玩意啊。不过希望学完这课,大家能够有拨云见雾的感觉。

到目前为止,我们已经学习了不少Linux的命令了,也已经比较熟悉命令行的用法了。其最基本用法是这样的:

在终端输入命令(比如输入ls命令)。

命令的运行结果显示在终端中。

但是我们还不知道的是:其实我们可以重定向命令的运行结果。

重定向,是什么意思呢?简单来说,就是我们可以把本来要显示在终端的命令结果,输送到别的地方:

到文件中或者作为其他命令的输入(命令的链接,或者叫命令管道)。

把两个命令连起来使用,一个命令的输出作为另一个命令的输入,这就构成了管道。

管道的英语是pipeline。你可以想象一个个水管,连接起来。这一个水管流出来的水(输出),如果接上另一个水管,水是不是就流入另一个水管,成为另一个水管的输入了?

当然了,在计算机科学中,流(英语是stream)的含义是比较难理解的,也比较丰富,不同的情况下含义也不太一样。如果把它比作水流可能不完全。

知乎上就有一篇帖子,大家可以看看:

《如何理解编程语言中「流」(stream)的概念?》

http://www.zhihu.com/question/27996269

我们常可以看到这样的字样:位元流,字节流,资料流,视频流,音频流,流媒体,流算法,流处理,数据流挖掘,等等。

在维*基百科中,流的简单定义是这样的,供大家参考:

《In computer science, a stream is a sequence of data elements made available over time. A stream can be thought of as items on a conveyor belt being processed one at a time rather than in large batches.》

以上这段英语翻译过来大致意思是(有点难翻译...翻得不好不要拍我):

《在计算机科学中,流是时间上可用的一系列数据元素。我们可以把流比喻成传送带上的物件,每个时间点传输一个,而不是多个打包传输。》

(翻得连我自己都快吐了...如果要扔我鸡蛋请再多扔几个面团过来,这样我可以做鸡蛋灌饼)

前面说了,我们会学习如何把命令的输出结果重定向到其他地方:

哪里:文件或者另一个命令的输入。

如何实现:通过在命令间插入特定的符号(这些符号可以被称为《重定向流》符号)。下面我们会学到,有好几种符号。

可以用下图来做一个小结:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

可以看到,命令的输出可以有三个去向:

终端

文件

其他命令的输入

到目前为止,我们只用过第一种形式:把命令的输出结果显示在终端。

我们岂能就此罢休呢对吧,肯定要乘胜追击啊。一不做二不休啊。

重定向流从Unix时代就已经是很重要的概念了,后来Linux出现,重定向流的原理依旧沿用。

重定向流将会改变我们看待终端命令行的方式,所以这课很重要。

借着这一课,我们将把我们的命令行的造诣提升到另一个层级。如果之前是命令行的小学,那么这一课学完就基本可以初中毕业了。

你也许看到过一些Linux高手输入命令,经常会输入一大串,然后回车。这一大串命令中很可能就用到了我们今天学的流,管道和重定向。

>和>>:重定向到文件

我们先从最简单的开始。最简单的操作就是把命令的输出结果重定向到文件中,就不会在终端显示命令运行结果了。

准备工作:再谈cut命令

在开始学习>和>>这两个符号的用法之前,我们需要创建一些文件。

在创建文件之前,我们来谈谈cut命令的进阶用法。cut是英语《剪切》的意思,用于从文件中剪切出来一部分内容。

上一课《【Linux探索之旅】第三部分第一课:数据处理,慢条斯理》中我们学习了cut命令,但没有深入讲解,只讲了比较基本的用法(-c参数:根据字符数来剪切)。

我们再来学习一下cut命令的其他参数。

cut命令进阶:根据分隔符来剪切

我们来看一种特殊的文件形式:CSV格式。

CSV是Comma Separated Values的缩写,翻成中文是《逗号分隔值》。

以下摘自百度百科:

=================

《逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。》

=================

CSV文件的后缀名是.csv,通常可以被Excel等软件打开,打开之后会把分隔符隔开的各个数值填充到表格里。

我们来构建一个CSV文件。因为我们要用逗号作为分隔符,来学习cut命令的进阶使用:根据分隔符来剪切。

假设我们有一个人数不多的班级,作为老师我们需要统计新近一次考试的成绩。我们为此制作了一个表格,并按照顺序把数据写入表格。

我们的CSV文件的内容可以如下,我们用Nano这样的文本编辑器来编写这个CSV文件,并且取名:notes.csv (note是英语《成绩》的意思)。

Mack,95 / 100,很不错

Matthew,30 / 100,跟平时一样水

Louise,70 / 100,有进步

Luke,54 / 100,接近平均分了

John,68 / 100,不错,但还可以更好

Samuel,100 / 100,总是那么完美

David,40 / 100,退步挺大呀

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所示,我们的notes.csv文件中每一行由三部分组成,每部分由一个逗号分隔:

学生名字

成绩(满分是100分)

评语

现在假如我们要从notes.csv文件中提取名字那一列,怎么办呢?我们不能用cut命令的-c参数啊,毕竟每个名字的字符数不相等。

聪明如你应该想到了。是的,我们看到文件中每一行的每一部分是用分隔符来隔开的,所以我们可以这样做:

需要用到两个参数:

-d参数:d是delimiter的缩写,是《分隔符》的意思。用于指定用什么分隔符(比如逗号,分号,双引号等等)。

-f参数:f是field的缩写,是《区域》的意思。表示剪切下用分隔符分隔的哪一块或哪几块区域。

我们的notes.csv文件是用逗号来分隔三个部分的,我们要剪切下来的是名字那一列,也就是第一部分。因此我们可以这样使用:

cut -d , -f 1 notes.csv

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

怎么样,很不错吧。我们通过cut命令的两个参数就实现了从notes.csv文件中剪切下第一部分(名字)的想法。

那如果我们只想剪切下评语部分呢?评语是第三部分:

cut -d , -f 3 notes.csv

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

那如果我们要第一和第三部分呢?可以这样:

cut -d , -f 1,3 notes.csv

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

同样地,我们可以用 cut -d , -f 2- notes.csv 来剪切第二部分直到最后的内容:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

好了,现在准备工作做好了,我们可以来学习重定向流符号了。

>:重定向到新的文件

我们知道虽然我们刚才用cut命令从notes.csv文件中剪切出来一些部分,但原始的notes.csv文件是不变的。

我们现在想要将剪切出来的部分储存到一个文件中,而不是像之前那样显示在终端里。

(为了方便演示,我们在家目录下新建一个redirect目录,redirect是英语《重定向》的意思。将之前的notes.csv文件放到这个目录下,再用cd redirect命令定位到这个目录)

我们需要用到>这个神奇的符号,如果你是美式键盘,那么可以在句号那个键找到这个符号,在句号的上面。所以要输入这个符号,可以用Shift加上句号那个键。做网络前端开发的程序员应该对这个符号不陌生,因为HTML语言里到处是<>这对符号。

这个符号可以将命令的输出结果重定向到你自己选择的文件中。例如:

cut -d , -f 1 notes.csv > students.txt

student是英语《学生》的意思。如果你运行上述命令,那么终端不会有任何显示。因为我们将cut命令的运行结果(剪切了名字那一列)重定向到students.txt文件中了。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

可以看到,我们用cat命令打印了student.txt文件的内容,正是cut -d , -f 1 notes.csv 这句命令的运行结果。

我们用ls命令查看redirect目录下的文件,发现多了一个students.txt文件。

怎么样,>这个符号很有用吧。不过使用时要小心,因为>符号会把输出重定向到文件中,如果此文件不存在,则新建一个文件;如果此文件已经存在,那就会把文件内容覆盖掉(清除原有内容,然后写入文件),而且是不会征求用户确认的。

有时候,我们既不想将命令的输出显示在终端,又不想将其储存到文件中,怎么办呢?

Linux中有一个俗称《黑洞》的文件,就是 /dev/null

null是英语《无,空》的意思。

/dev/null 文件是特殊文件,不是一个目录。此文件具有唯一的属性:它总是空的。它能使发送到/dev/null 的任何数据作废,就好像这些数据掉进了无底的黑洞一般。

因此,假如我们不需要在终端显示刚才那个cut命令的结果,也不想存储到文件里,那么可以这么做:

cut -d , -f 1 notes.csv > /dev/null

>>: 重定向到文件末尾

我们已经知道,单独一个>符号可以实现重定向到新的文件(覆盖文件内容),那么两个连在一起的>符号有什么作用呢?

>>的作用与>是类似的,不过它不会像>那么危险(如果文件已经存在,>符号会覆盖文件内容),而是将重定向的内容写入到文件末尾,起到追加的作用。如果文件不存在,也会被创建。

我们就来实践一下:

cut -d , -f 1 notes.csv >> students.txt

因为我们上一个例子中已经用>符号来重定向名字那列的内容到students.txt文件中了,所以上面的命令会追加同样内容到students.txt的末尾。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

我们用cat命令打印了students.txt文件的内容,可以看到有两遍notes.csv中名字列的内容。

>>符号在很多情况下非常有用,比如你人不在电脑前,而你又想让终端为你记录程序运行的结果,就可以在一个日志文件的末尾一直写入。例如:

command >> results.log

小结

我们方才学习了两个重定向流符号:

>:重定向到文件中。如果文件已存在,则覆盖文件内容;文件不存在,则创建文件。

>>:重定向到文件末尾。文件不存在,则创建文件。

可以用下图演示两个符号的原理:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

2>,2>>,2>&1:重定向错误输出

怎么样,流的重定向是不是很有趣?那么我们继续学习其他的重定向流符号。

我们首先来学点新知识。

stdin,stdout,stderr:标准输入,标准输出,标准错误输出

这三个又是什么东东?这一课新东西果然多。

一般学编程,到某个阶段,总应该会碰到这三位仁兄的。所以既然逃不了,不如勇敢来面对。

对于我们的终端命令行,我们从键盘向终端输入数据,这是标准输入,也就是stdin。

终端接收键盘输入的命令,会产生两种输出:

标准输出:stdout。指终端输出的所有信息(不包括错误信息)。

标准错误输出:stderr。指终端输出的错误信息。

第一个stdout就是我们到目前为止看到的那些Linux命令的正常运行结果,比如在终端中运行ls命令,我们以前也看到了它列出当前目录下所有文件。

那什么是标准错误输出呢?其实我们以前也看到过,只是见得不多而已。

我们用一个例子来说明。

假设,我们运行cat notes.csv命令,想要显示notes.csv文件的内容。将会有两种结果:

如果一切顺利(notes.csv文件存在于当前目录,而且我们有权限这么做),那么终端就会显示其内容。这是标准输出。

如果出错(比如notes.csv文件不存在),那么终端就会显示错误信息。这是标准错误输出。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所示,我们在redirect这个目录中运行cat notes.csv时,因为文件存在,而且我们有权限对其执行cat命令,所以打印出了文件内容。这就是标准输出。

接着,我们用cd .. 命令定位到了上一级目录,也就是用户的家目录,在这个目录中我们并没有创建notes.csv文件,所以cat notes.csv命令自然就输出了错误信息:No such file or directory,翻译过来就是《不存在此文件或目录》。这就是标准错误输出。

默认情况下,标准输出和标准错误输出都会显示在终端,这也是为什么我们之前对它们的区别并没有那么在意的原因,因为长得挺像的,都在终端输出。

我们可以用下图来演示:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

这三个你也可以把它们看作流:

stdin:标准输入流。standard input的缩写。标准输入是指输入至程序的数据(通常是文件)。程序要求以读(read)操作来传输数据。并非所有程序都要求输入。如dir或ls程序运行时不用任何输入。 除非重定向,输入是预期由键盘获取的。 标准输入的文件描述符为 0 (零);在POSIX <unistd.h> 的定义是 STDIN_FILENO;相对应的 <stdio.h> 变数为 FILE* stdin ;类似地, <iostream> 变数为 std::cin 。

stdout:标准输出流。standard output的缩写。标准输出是指程序写输出数据的流。程序要求数据传输使用写的运算。并非所有程序都要求输出。如mv或ren程序在成功完成时是没有输出的。 除非重导向,输出是预期显示在终端上的。 标准输出的文件描述符为 1 (一)。POSIX <unistd.h> 定义是 STDOUT_FILENO;相对应的 <stdio.h> 变数为 FILE* stdout ;类似地, <iostream> 变数为 std::cout 。

stderr:标准错误输出流。standard error的缩写。标准错误输出是另一个输出流,用于输出错误消息或诊断。它独立于标准输出,且标准输出和标准错误输出可以分别被重定向。标准错误输出的文件描述符为 2 (二);POSIX <unistd.h> 定义为 STDERR_FILENO;相对的 <stdio.h> 变数 FILE* stderr。C++ <iostream> 的变数为: std::cerr。

文件描述符  名字  解释
0  stdin  标准输入
1  stdout  标准输出
2  stderr  标准错误输出
那什么是文件描述符呢?

文件描述符的英语是File Descriptor,简称fd。

文件描述符是计算机科学中的一个术语,要完全讲清楚可能要用单独的一课。我们就不深究了。

文件描述符是一个用于表述指向文件的引用的抽象化概念。这定义本身也有点抽象。我们不需要太深入了解。大致只需要知道:

《文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向操作系统内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符》。

文件描述符通常是Unix,Linux等系统的概念。在Windows中,也有类似的概念,但是Windows中称为《句柄》,就是handle。

好了,重新回到我们的话题。刚才我们已经学习了用>和>>两个符号可以将输出重定向到文件中,那么我们在出错的情况下是不是也可以用>和>>将标准错误输出也重定向到文件中呢?我们来试试:

cat not_exist_file.csv > results.txt

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所示,因为 not_exist_file.csv 这个文件不存在(正如其名),所以产生了错误信息。但是这个错误信息却并没有如我们所愿的写入到results.txt文件中,而是仍旧在终端输出了。这是为什么呢?不是说好的>符号用于重定向输出到文件的吗?

其实,>和>>符号只是将标准输出重定向到文件。并不能将标准错误输出重定向到文件。

那么我们要重定向标准错误输出,该怎么办呢?

我们就要用到 2> 这个符号,是的,就是在>这个符号左边紧挨着写一个2。

为什么是2呢?记得上面说的吗?标准错误输出的文件描述符是2,所以这里的2表示标准错误输出。如果没有2,单独的>符号就是重定向标准输出(文件描述符为1)。

我们补充一下刚才的命令:

cat not_exist_file.csv > results.txt 2> errors.log

这个命令里有两个重定向:

> results.txt:将标准输出重定向到results.txt文件中。

2> errors.log:将标准错误输出重定向到errors.log文件中。

也就是说,假如 not_exist_file.csv这个文件确实存在,将其内容写入results.txt文件中;假如文件不存在,将错误信息写入errors.log文件中。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所示,我们运行了cat not_exist_file.csv > results.txt 2> errors.log这个命令,因为not_exist_file.csv这个文件不存在,所以results.txt文件是空的;errors.log文件的内容是错误信息。

类似地,2>>符号用于将标准错误输出重定向到文件末尾。

合并输出

上面我们学习了如何将标准输出和标准错误输出分别重定向到不同文件。但是有的时候,我们比较任性,我们就想把标准输出和标准错误输出都重定向到同一个地方。怎么做呢?

须要使用 2>&1 这个组合符号。

看着怪怪的对吧?由四个字符组成。这个符号的作用是:将标准错误输出重定向到与标准输出相同的地方。

我们用实例演示一下:

cat not_exist_file.csv > results.txt 2>&1

上面的命令的作用是:将cat not_exist_file.csv这个命令的所有输出(标准输出和标准错误输出)都重定向到results.txt文件中。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所示,运行cat not_exist_file.csv > results.txt 2>&1命令之后,因为not_exist_file.csv这个文件不存在,但又因为加了2>&1这个符号,所以标准输出(为空)和标准错误输出(cat: not_exist_file.csv: No such file or directory)都重定向到results.txt文件中了。

然后大家是否觉得要将标准输出和标准错误输出都重定向到文件末尾,应该是这样写:2>>&1 呢?

其实不然,这样是不对的。我们还是保持2>&1这个组合不变,只改变前面的符号就行了。例如:

cat not_exist_file.csv >> results.txt 2>&1

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

可以看到,又追加了一条错误信息到results.txt文件中。

小结

2>:将标准错误输出重定向到文件。如果文件已经存在,则覆盖文件内容;如果不存在,则创建文件。

2>>:将标准错误输出重定向到文件末尾。如果文件不存在,则创建文件。

2>&1:将标准输出和标准错误输出都重定向到一个地方。

用下图来演示:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

上图中,我故意没有加>>和2>>,不然这图就太复杂了。其实>和>>,2>和2>>的区别就是前者覆盖文件内容,后者追加内容到文件。

<,<<:从文件或键盘读取

到目前为止,这一课我们只讲了如何重定向命令的输出,也就是决定命令输出的信息的去向。那么接着我们可以做一点相反的事情:决定命令的输入来自哪里。

当然了,上面也说了,不是所有的命令都有输入,也不是所有的命令都有输出。

到目前为止,我们的命令的输入都来自于后面接的参数,这些参数有些是文件名,有些是目录名,等等。

但我们其实可以使命令的输入来自于文件或者键盘输入。如下图所示:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

<:从文件中读取

看到这个<符号,是不是想到了之前的>符号呢?

是的,这对孪生兄弟,原理类似但是功能正相反。<符号用于指定命令的输入。

我们用一个简单的例子来演示:

cat < notes.csv

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所示,cat < notes.csv的运行结果和cat notes.csv (不用重定向流符号)一模一样,都是在终端打印notes.csv的内容,那我们为什么需要<符号呢?

事实上,虽然cat < notes.csv的运行结果和cat notes.csv一样,但是原理却不一样:

cat notes.csv :这种情况下,cat命令接受的输入是notes.csv这个文件名,那么它要先打开notes.csv文件,然后打印出文件内容。

cat < notes.csv :这种情况下,cat命令接受的输入直接是notes.csv这个文件的内容,cat命令只负责将其内容打印。而打开文件,将文件内容传递给cat命令的工作则交给shell程序(也就是控制终端的程序)来完成。

所以,虽然结果看似一样,但是中间的过程确实不一样的。

<<:从键盘读取

<<符号的作用是将键盘的输入重定向为某个命令的输入,很多情况下都很有用。

我们用实例来说明:

sort -n << END

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所示,输入这条命令之后,回车,终端就进入了键盘输入模式,看到那个>符号和其后闪动的光标了么?

就是让你输入数据的。

我们知道sort -n的作用是按照从小到大进行排列。那么我们就输入一些数值吧(每输一个数值,用回车键来换行,接着输入下一个数值,输入END来结束输入,END被称为结束字符串。当然了,你可以用其他字符串,比如haha,nihao,不一定要用END):

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

可以看到,sort -n命令将我们输入的一串数值进行了由小到大的排序。

我们再试试其他命令与<<符号的配合,这次我们用wc命令吧,wc命令用于统计字符等,如果配合-m参数就是统计字符数。

wc -m << END

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

可以看到,《How many characters are there in this sentence ?》这句话中有49个字符。

这句话翻成中文就是《这句话中有多少个字符?》

小结

<:将命令的输入重定向为文件内容。

<<:将命令的输入重定向为键盘输入,以逐行输入的模式(回车键换行)。所有输入的行都将在输入结束字符串(例如上面例子中的END)之后发送给命令。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

当然了,我们也可以将之前学习的输出重定向符号和这一节的输入重定向符号结合使用:

sort -n << END > numbers_sorted.txt 2>&1

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所见,以上命令将sort -n命令对数值排序的结果都输入到numbers_sorted.txt文件中,如果有错误信息也输入。

|:管道

好了,终于来到本课的最后一节了。

是不是有点累呢?如果是的话,可以去烤一只烤鸭。为什么小编不像以前一样说烤鸡了呢?是因为最近有一对好友夫妇在法国Aix en Provence开了一家烤鸭店,他们的公众号发了几张诱人的烤鸭照片,看得小编直流哈喇子。但是吃不到啊,小编住在Nice附近,离Aix en Provence有近3个小时火车的路程。唉,以后去吧~

好了,不扯烤鸭了,言归正传。

这一节要学的符号,将会成为你以后Linux生涯中最常用的符号之一,使用率绝对高过这一课学的其他符号。

这个符号就是所谓的《管道符号》:|

是的,就是美式键盘上位于反斜杠那个键的那个符号,要输入这个符号,需要使用Shift + \

|符号既然被称为《管道符》,那么其作用就是《建立命令管道》咯。

是的,还记得本课开篇的时候我们提到的那个比喻吗?一个命令的输出可以作为另一个命令的输入,就好像将两根水管接起来一样,前一根水管流出来的水就会流入后一根水管了。

管道也算是重定向流的一种。

原理

将两个命令连成管道,这是什么意思呢?简单的说就是将一个命令的输出作为另一个命令的输入,如下图所示:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

大致来说:命令1的输出立即会变成命令2的输入。使用这个原理,我们可以用|符号连接无穷多个命令,构成很长的命令管道。

管道符绝对使Linux命令的威力增加N倍。之前我们也说了,Linux中的命令(很多都是从Unix时代承袭下来的),每一个的功能虽然有限,但是却在它们自己的岗位上尽忠职守,工作做得棒棒哒。所以单独一条Linux命令可能功能有限,但是一旦《铁索连环》,那可是会结合各个命令的功能,其强大不难想见。

实践

我们用几个实例来学习管道吧。

按学生名字排序

你应该还记得我们的notes.csv文件,其中有三部分,用逗号隔开的,第一部分是学生名字,第二部分是成绩,第三部分是评语。

之前我们用cut -d , -f 1 notes.csv 命令来剪切了名字那一列。如果你还记得我们前一课学的sort命令,它是用于排序文件内容。

那么为什么不把这两个命令用管道符连接起来呢?我们可以用sort命令对cut命令提取到的名字列进行排序:

cut -d , -f 1 notes.csv | sort

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

如上图所见,我们用sort命令对名字列按照首字母的字典顺序进行了排序。

怎么样,管道是不是很有意思?

如果我们将上面的命令再扩充一下,配合之前学习的输出重定向符号,就变成了这样:

cut -d , -f 1 notes.csv | sort > sorted_names.txt

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

可以看到,我们将sort命令排序的结果重定向到sorted_names.txt文件中了。

根据大小排序目录

之前我们学过,du命令可以深入遍历当前目录下每个子目录,把所有文件的大小都做一个统计。

我们可以用cd命令来回到我们的家目录。然后运行du命令。

问题是:du命令要运行挺久的,因为小编家目录下文件很多。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

单独用du命令的缺点我们也有目共睹了,一是可能要运行很久(如果文件很多),二是显示结果没有排序,杂乱无章。

但如果我们这样做就会清爽很多:

du | sort -nr | head

还记得head命令的用法么?如果不用-n参数指定显示行数,那么head会默认显示前10行。

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

所以以上命令的作用是:

du 深入遍历当前目录下每个子目录,把所有文件的大小都做一个统计

sort -nr sort命令的-n参数是按以数值来排序(此处是文件大小)排序,默认是小的在前;-r参数是倒序排列,有了-r参数,-n参数就变成大的数值在前了

head 列出前十个最大的数值(这里是文件大小)

列出包含关键字的文件

还记得我们的好朋友grep命令吗?之前的课中有学过,这个命令很强大,可以在文件中查找关键字,并且显示关键字所在的行。但有时,我们会觉得grep显示的信息太冗长了。每一行不仅有文件名,还有关键字出现的那一行文本,等等。

我们可以运行以下命令试试:

sudo grep log -Ir /var/log | cut -d : -f 1 | sort | uniq

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

这个命令做了什么呢?让我们一步步来分解:

sudo grep log -Ir /var/log :遍历/var/log这个目录及其子目录,列出所有包含log这个关键字的行。-I参数用于排除二进制文件。-r参数用于递归遍历。sudo命令是为了以root身份查找系统文件夹/var/log。

cut -d : -f 1 从命令1的输出结果中只剪切出文件名那一列(由冒号分隔的第一个区域)。

sort 将文件名的列以首字母的字典顺序进行排序。

uniq : 去掉重复的文件名。

小结

小结很简单,因为管道符的基本作用比较简单,就是将一个命令的输出重定向为另一个命令的输入。如下图所示:

Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下

记住这个基本原理就好了。

好了,终于这一课结束了。是不是有点晕,如果觉得还没怎么掌握,那需要再读一遍本课程,参考一些课外读物,自己在终端上多练习。尽情发挥你的想象力,来创造出各种命令的组合吧。

总结

Linux命令的结果(标准输出),我们不一定要显示在终端里,也可以将其存放在一个文件里,只需要在命令后加上 > 符号,然后接文件名就可以了。例如 ls > file_list.txt 就会把ls命令的结果(当前目录所有文件的列表)存放到file_list.txt文件中,不在终端显示了。

>> 符号可以追加内容。>符号会把文件内容清空,再写入。如果文件已经存在,那么>>符号会在文件末尾追加写入内容。

2>和2>>符号用于重定向标准错误输出到文件中。2>&1符号用于将标准错误输出和标准输出重定向到相同地方。

<符号重定向命令的输入为文件内容,<<符号重定向命令的输入为键盘输入。

管道符号|可以将命令连接起来,好像一个个对接的管道一样,前一个命令的输出成为后一个命令的输入。

第三部分第三课预告

今天的课就到这里,一起加油吧!

下一课我们学习:监视系统活动,滴水不漏

新朋友请关注「程序员联盟」微信搜公众号 ProgrammerLeague

程序员联盟官网:

coderunity点com

程序员联盟论坛:

coderunity点com/bbs/

小编微信号: frogoscar

小编邮箱: enmingx@gmail.com


【Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下】
http://toutiao.com/a6193788933316428033/?iid=3041659310&app=news_article&tt_from=android_share&utm_medium=toutiao_android&utm_campaign=client_share

作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/8256/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2015-9-14 11:55
评论列表
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]