重定向是什么

在计算机领域,重定向是大多数命令行解释器所具有的功能,包括各种可以将标准流重定向用户规定地点的Unix shells。Linux作为一种类UNIX系统,支持重定向。Linux下重定向是指对原来系统命令的默认执行方式进行改变,比如说有时候我们不想看到输出结果到屏幕,而是希望输出到某一文件或设备中,就可以通过Linux重定向来进行这项工作。

下图是本篇文章的思维导图:

在学习重定向之前,我们要了解程序的输入和输出。程序=指令+数据,每个程序的执行需要读入数据和输出数据。早期的计算机通过纸带打孔读入数据,通过二极管发光输出数据。今天我们不再使用这种古老的设备了,那么,思考一下我们的输入来自哪?输出又输到哪呢?

首先,我们来了解一下linux的文件描述符。文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。在linux下,打开的文件都有一个文件描述符(file descriptor)。

linux启动后,会默认打开3个文件描述符,给程序提供三种I/O设备,我们可以在linux下输入tty查看当前终端, cd /etc/fd 进入目录,可以看到下图的0,1,2三个文件,/dev/pts/1是当前终端,这代表:

    标准输入(standard input) -0 默认接受来自键盘的输入

    标准输出(standard output)-1 默认输出到终端窗口

    标准错误(standard error) -2 默认输出到终端窗口

对于任何一条linux 命令执行,过程如下图所示:

 

一个linux命令执行了:

先有一个输入(standard input):输入可以从键盘,也可以从文件得到

命令执行完成(standard output):成功了,会把成功结果输出到屏幕当前终端窗口或者输出到文件中

命令执行有错误(standard error):会把错误默认输出到当前终端窗口或者输出到文件中

 

2 I/O重定向

输出重定向

格式:command [1或2] > device或file或其它

上面这条命令的意思是:将一条命令执行结果(标准输出,或者错误输出,本来是默认打印到当前终端设备即屏幕上面的),

重定向其它输出设备(文件,文件操作符,等等),1,2分别是标准输出,标准错误输出。

实例:

当我们执行一条命令,默认打印到当前终端设备即屏幕上面,如下图

如果不想在屏幕上看到命令执行结果,这时候就需要用到输入输出重定向啦。

(1)标准输出 >

echo hello > a.txt,仔细看,发现了什么?本来应该输出到屏幕上的hello不见了,查看 a.txt文件,我们发现hello被写进了a.txt文件里,这时就已经将命令执行结果重定向到文件里了。

当然了,输出不只能重定向到文件中,下面来试试将输出重定向到其它终端设备吧!

我打开了两个终端设备,分别是/dev/pts/1和/dev/pts/2。在/dev/pts/1终端执行echo hello > /dev/pts/2,回车,屏幕上没有输出结果,这时我们切到/dev/pts/2终端,在屏幕上看到了"hello"这个输出结果,也就是说,输出可以重定向到其它终端设备。

重定向中,标准输出1是默认项,所以1可以写也可以不写,下图中,可以看到标准正确输出中加不加结果无变化

(2)标准错误输出    2>

但是输出标准错误时必须写上2,不要忘记哦。

            

(3)标准输出和错误输出各自定向至相同或不同位置

格式:COMMAND > file/device 2> file/device

有时候我们既要输出正确结果,又要输出错误结果,这时候可以标准输出和错误输出各自定向至相同或不同位置。下面是具体实例:

存在/etc/passwd这个文件,但是当前test目录为空目录,并没有passwd文件,查询这两个文件有错误输出也有正确输出,直接执行ls /test/passwd /etc/passwd >/dev/pts/3 ,会看到错误输出显示在当前终端屏幕上,这代表没有重定向成功。

正确输出显示在/dev/pts/3终端屏幕上,重定向成功了。该怎么办呢?别忘了我们刚才提到的错误输出要加上2

这该怎么办呢?别着急,别忘了我们刚才提到的错误输出要加上2,我们分别把标准输出和错误输出重定向到/dev/pts/3中。执行ls /test/passwd /etc/passwd >/dev/pts/3 2>/dev/pts/3 这条命令,就可以把它们都显示在/etc/pts/3终端上啦!

当然,重定向位置也可以不同,将标准输出和错误输出各自定向至不同位置。

标准输出重定向到/dev/pts/2

标准错误输出重定向到/dev/pts/3

如果重定向到相同位置,这样写就比较麻烦,要写两次相同位置,有没有更好的方法呢?,当然是有的!

下面介绍三种把所有输出重定向到文件/设备的方法:

我们可以将错误输出转为正常输出 2>&1或者将正确输出转为错误输出 1>&2,就可以将标准输出和错误输出重定向到同一文件或设备了。

  • 将错误输出转为正确输出

格式:command > file/device 2>&1

执行 ls /test/passwd /etc/passwd >/dev/pts/4 2>&1命令

切换到/dev/pts/4终端,可以看到,标准输出和错误输出结果都显示了

 

  • 正确输出转为错误输出

格式:command 2> file/device 1>&2

执行ls /test/passwd /etc/passwd 2>/dev/pts/5 1>&2

切换到/dev/pts/5终端,可以看到,标准输出和错误输出结果都显示了

            

  • 把所有输出重定向到文件/设备

格式:command &> file/device

执行ls /test/passwd /etc/passwd &>/dev/pts/5

切换到/dev/pts/5终端,可以看到,标准输出和错误输出结果都显示了

 

(4)>和>>的区别

>:当文件不存在时创建,当文件存在时覆盖

>> :当文件不存在时创建,当文件不存在时追加

示例:

执行ls a.out 可以看到test目录下本来不存在a.out文件,通过> filename 可以创建文件。

将"hello"写入a.out文件,查看a.out文件,可以看到"hello"这时再利用>将"world" 写入a.out文件,可以看到a.out文件中"hello"被"world"覆盖掉了,只剩下"world",即文件存在时覆盖原来的内容。

command >> filename 追加内容到文件中。下图中原来a.out文件中只有"world",通过>>追加了"nihao"到a.out文件中

文件被覆盖容易造成数据的丢失,为了安全起见,可以执行set –C 防止覆盖,在防止覆盖模式下,临时想覆盖文件可以执行command >| filename,强制             覆盖文件,执行set +C允许覆盖文件。

(5)合并多个程序的标准输出

利用括号()可以将多个程序的标准输出都输入到一个文件或设备上

示例:(cal 7 2007;cal 1 2017)> all.txt,可以看到2017年7月和1月的日历都写入了all.out文件中。    

输入重定向

输入重定向的符号是 <

默认接受来自键盘的输入,当我们需要从文件中获取数据时,可以利用输入重定向。

很多命令需要标准输入,例如cat,mail等

利用标准输入发邮件。mail.txt文件中的内容是"hello,world",mail命令从mail.txt文件中得到输入发给xiaomi这个用户,主题为"hello"

执行su – xiaomi ,切换到xiaomi用户,查看邮件是否成功,从图中红色框选部分可以看到刚才所写的邮件内容,证明发邮件已经成功。

3 tr命令

接下来我们要学习一个功能特别实用的工具——tr,它既能支持标准输入,也能支持标准输出。哦?那有人该问了,它是做什么用的。答案来了,tr转换、压缩或者删除从标准输入得到的字符,并写入标准输出。

格式:tr [OPTION]... SET1 [SET2]

选项:

-c–C --complement:取字符集的补集

-d--delete:删除所有属于第一字符集的字符

-s--squeeze-repeats:把连续重复的字符以单独一个字符表示

-t--truncate-set1:将第一个字符集对应字符转化为第二字符集对应的字符

对应的字符:

[:digit:]:任意数字,相当于0-9

[:lower:]:任意小写字母

[:upper:]: 任意大写字母

[:alpha:]: 任意大小写字母

[:alnum:]:任意数字或字母

[:blank:]:水平空白字符

[:space:]:水平或垂直空白字符

[:punct:]:标点符号

[:print:]:可打印字符

[:cntrl:]:控制(非打印)字符

[:graph:]:图形字符

[:xdigit:]:十六进制字符

使用:

tr SET1 SET2

tr'a-z''A-Z',将输入的小写字母转化为大写字母。注意:有两个字符集

如果两个字符集长度一样,就对应字符进行转换,字符集之外的字符不转换

两个字符集不一定一样长,这时会发生什么事情呢?

第一个字符集长度比较长的情况下,进行转换时,用第二个字符集的最后一个字符替换第一个字符集比第二个字符集长度超出的部分字符。字符集'abcd'比'xyz'多一个字符,执行tr 'abcd' 'xyz'命令,输入'abcd',可以看到转化的字符为'xyzz',第二个字符集的最后一个字符'z'替换了多出的'd'

如果想只要对应的字符进行转换,可以加上选项-t

tr -t 'abcd' 'xyz'

如果第二个字符集长度比较长,进行转换时,只转化与第一字符集相对应的字符,第二字符集多出的字符并不参与转换。

r

    

上面是从屏幕上获得输入,tr也可以接受从文件中导入的标准输入

tr'a-z''A-Z'</etc/issue,该命令会把/etc/issue中的小写字符都转换    成大写字符

 

tr–d abc< a.out删除a.txt文件中的所有'abc'中任意字符

tr -s 'a' 把得到的输入中多个a用一个表示

tr -c 'a' 'A' < a.txt ,a.txt文件中内容为abcd,转换后,'bcd'还有换行符被转换为'A'

 

4 管道

管道(使用符号"|"表示)用来连接命令

命令1 | 命令2 | 命令3 | …

将命令1的STDOUT发送给命令2的STDIN,命令2的STDOUT发送到命令3的STDIN

STDERR默认不能通过管道转发,可利用2>&1 或|& 实现

最后一个命令会在当前shell进程的子shell进程中执行用来组合多种工具的功能

ls | tr 'a-z' 'A-Z',将ls的结果发送给tr 'a-z' 'A-Z'

5

 

5 tee命令

命令1 | tee[-a ] 文件名| 命令2

把命令1的STDOUT保存在文件中,做为命令2的输入,STDOUT既可以显示在屏幕上,又可以保存至文件中。

tee -a 追加,如果不加-a,当文件已存在时,则覆盖

使用:

保存不同阶段的输出

复杂管道的故障排除

同时查看和记录输出

将当前系统登录用户的信息转换为大写后保存至/tmp/who.out文件中

who | tr 'a-z' 'A-Z' | tee -a /tmp/who.out

 

好了,这篇文章就介绍到这里了。更多内容请查看man文档或者去官方网站查询。

Logo

更多推荐