相关文章
Linux:chgrp、chown、chmod权限属性更改指令
Linux: 磁盘状态观察命令lsblk、blkid
Linux:df、du容量查询指令
1、标准流文件
数据流重定定向由字面上的意思来看,就是将数据定向到其他地方去,事实也是如此,数据流重定向就是将本来出现在屏幕(终端)上的数据,传输到其他地方(如文件或设备)。这在Linux命令行模式下面很重要,尤其是如果我们想要将某些数据存储下来时,就更有用了。
如果你执行一个命令,这个命令可能会由文件读入数据,经过处理后,再将数据输出到屏幕上。标准输入(stdin)、标准输出(stdout)和标准错误(stderr)的默认设备是终端,我们可以验证这一点,我们可以在/dev目录下找到这三个标准流文件,他们其实就是三个文件描述符。
可以看到,它们只是到self进程中的fd(文件描述符)的符号链接,接着我们去/proc中找到这三个文件,结果发现它们也是链接文件,链接到设备pts/0,其实这就是我在GNOME中打开的虚拟终端设备pseudo-terminal slave(即这个终端窗口),因为它是GUI环境虚拟产生的,因此得名。这与之前所说的标准输出、标准输入和标准错误默认是终端是吻合的。
但这是我们也许可以发现问题当我们打开第二个虚拟终端,再查看/proc/self/fd目录时,问题出现了同样的/proc/self/fd/0文件,居然在不同的终端链接到了不同的虚拟终端(/dev/pts/1),想必已经有人猜到了,其实/proc/self/目录本身就链接到了其他目录,用ls验证一下,确实如此。
那么这个4567又是什么进程呢?它就在/proc目录下,我们尝试找到它。但居然发现它压根不存在,说明这个进程早已结束,看起来这里的self的链接对象似乎是在不断切换的,这才导致了之前里面fd目录下的描述符一会儿对应虚拟终端0,一会儿对应虚拟终端1。其实,self的链接对象是尝试当前正在访问self的进程,所以其实ls -l self时输出的4567对应的是ls这个进程,在ls命令执行完毕后,此进程当然不存在了,所以才找不到。bash父进程在创建ls子进程时,让其继承了自己的文件描述符,包括0,1,2这三个标准流的文件描述符,所以在用ls查看0,1,2这三个文件的链接对象时,显示的是虚拟终端,因为这是bash的默认标准输入输出设备。
现在,/dev/stdin、/dev/stdout和/dev/stderr链接到/proc/self/fd中的文件描述符,意图就很明显了,让所有进程(命令)使用自己的标准流来输入输出文件(虽然这看起来是废话),所有进程(命令)在创建时,都会继承到父进程的文件描述符(其中包括标准输入输出),因为默认这三个文件描述符对应的是终端屏幕,所以命令一般会输出到屏幕。(注意,如果是cat file)这类命令,并没有改变标准输入的指向,而是创建了新的文件描述符。
如果想要改变进程(命令)的标准输入输出,则需要使用重定向指令。
2、重定向的过程
使用<可将标准输入重定向到文件,使用方式为command < file;使用>可将标准输出重定向到文件,使用方式为command > file;使用2>可将标准错误重定向到文件,使用方式为command 2> file。
我们来看一下重定向的过程,使用sleep命令比较方便,因为它的执行时间较长。在命令后加&使命令后台执行,这样我们就可以继续使用命令行,我们使用命令的pid查询并看到了他的三个文件描述符继承了bash父进程,统统指向了虚拟终端,这和预期相符。
接着我们在sleep命令后使用>指令,将标准输出流重定向到一个文件(是否已存在不重要,如果否,bash则会创建这个文件,如果存在了,bash则会把这个文件清空)。
可以看到,文件描述符1这时的链接对象不是虚拟终端了,而是我们指定的文件,这就是重定向的原理,系统并没有新建文件描述符来指向我们重定向的文件,而是将原本标准输出的文件描述符重新指向了,所以原本会输出到虚拟终端的信息,都被输出到指定的文件中去了。
如果不想清空原本的文件内容,则可以使用<<、>>和2>>指令,这表示将在原内容上追加。
3、管道命令
可以使用管道命令|将两个命令的标准输入输出连接在一起,这很神奇,也是Linux中一个功能十分强大的特性,使用它可以让多个命令一个接一个地协作处理,我们来看一个例子。
使用ll | less命令,即可把ll本应输出到屏幕的信息,转交给less处理,即转移到less的标准输入中,就好像是将ll的标准输出和less的标准输入连接到了一起。这样你就可以利用less的功能前后翻动ll输出的信息了,如下图所示。
为了验证这一点,我们继续使用sleep命令进行测试,ps命令用于查询进程的pid。可以看到,sleep命令(pid5262)的标准输出连接到了pipe:[63913],而cat命令的标准输入也连接到了pipe:[63913],从而实现了两个命令的连接。