许多命令在执行的时候会有输出,这些输出包括标准输出和标准错误输出,默认都会输出到屏幕。 如果输出的数据量太多,就会对屏幕造成干扰,影响命令行的操作。而且很多数据还没来得及查看就被后面的输出覆盖掉了。 还有一些在后台运行的命令,我们也不希望这些数据输出到屏幕,而是通过数据流重定向功能将输出重定向(redirect)到磁盘文件或者输出设备例如打印机等。

什么是数据流重定向

回到顶部

命令包括标准输入、标准输出和标准错误输出。一般来说,一条命令的数据传输如下图所示:
linux命令数据传输 一条命令可以由标准输入读入数据,经过处理后再由标准输出(standard output)输出到屏幕,如果命令执行过程出现错误, 也会通过标准错误输出(standard error output)到屏幕
简单的说,标准输出指的是命令执行过程中产生的一些正常信息,而标准错误输出可理解为命令执行发生错误后所产生的错误输出。 大部分命令的输出都是标准输出,例如ls命令输出文件信息,cat命令输出文本文件内容。如果用cat命令查看一个不存在的文件:

              [peter@study ~]$ cat notexistfile
              cat: notexistfile: No such file or directory
            
由于notexistfile文件并不存在,所以cat就会输出一条错误信息,这条错误信息就是通过标准错误输出的。 默认情况下,不管是标准输出还是标准错误输出都是输出到屏幕上。这就会导致屏幕太乱,影响用户使用。 可以将standard output(简称stdout)与standard error output(简称stderr)分别输出到其他的文件或输出设备。

数据流重定向用到的特殊字符如下所示:

1. 标准输入(stdin) : 文件描述符为0 ,使用< 或 <<表示;
2. 标准输出(stdout): 文件描述符为1 ,使用 > 或 >>表示;
  >输出数据覆盖到文件:
  a. 若文件不存在,自动创建该文件。
  b. 如果文件存在,那么先将文件内容清空,然后再写入数据!
  >>输出数据追加到文件:
  a. 如果文件不存在,自动创建文件;
  b. 如果文件已存在, 将输出数据追加到文件末尾!
3. 标准错误输出(stderr): 文件描述符为2 ,使用2>或2>>表示;
>和>>默认重定向标准输出,如果需要将standard error output重定向,就需要用到2>和2>>。
和>、>>类似,2>将输出覆盖到文件而2>>将输出追加到文件。标准输出(stdout)的文件标识描述符是1, 而标准错误输出(stderr)是2, 所以这个2>就是重定向标准错误输出,而如果仅是>,则代表默认的文件描述符为1!
>或1> :以覆盖的方式将标准输出数据输出到指定文件或者设备;
>>或1>>:以累加的方式将标准输出数据输出到指定的文件或设备;
2> :以覆盖的方式将标准错误输出数据输出到指定文件或者设备;
2>>:以累加的方式将标准错误输出数据输出到指定的文件或设备;
注意1>>或2>>中间是没有空格的。

使用ls -al /输出根目录下的文件信息,并将输出重定向到rootfile文件中:

              [peter@study ~]$ ls -al / > ~/rootfile
              #由于输出已经重定向到了rootfile文件中,所以屏幕无任何输出信息
              [peter@study ~]$ ls -al
              total 1220
              drwxr-xr-x  39 peter peter   4096 Jan 26 16:04 .
              drwxr-xr-x   5 root  root    4096 Oct 24 14:26 ..
              ...省略...
              -rw-r--r--   1 peter peter   1690 Jan 26 16:04 rootfile
              ...省略...
            
执行ls -al / > ~/rootfile后,屏幕上没有任何输出信息,但是却在用户家目录下发现了rootfile文件, 我们通过cat观察该文件的内容会发现这正是ls -al /的输出。也就是说ls -al /本该输出到屏幕上的信息却被输出到~/rootfile文件了。

再次执行ls -al /home > ~/rootfile命令,查看rootfile文件会发现~/rootfile文件只有ls -al /home的输出数据,之前的内容被覆盖掉了! 也就是说>会覆盖掉文件原本的内容。
但是很多时候我们还是希望保留文件原本的内容,只是将新数据追加到文件的末尾即可。将>换成>>就可以了, 上面改成ls -al /home >> ~/rootfile即可。

一般普通用户执行find命令的时候,可能会由于权限的原因而产生一些错误信息。 例如以peter身份搜索/home目录下的.bashrc文件:

              [peter@study ~]$ find /home -name .bashrc
              find: '/home/wwwroot': Permission denied              # Standard error output
              find: '/home/initroot': Permission denied             # Standard error output
              /home/peter/.bashrc                                   # Standard output
            
我们会发现上面既有错误的输出信息也有正确的输出信息,>只会将标准输出(正确的输出信息)输出到文件中, 例如find /home -name .bashrc > list,list文件中只会有/home/peter/.bashrc这一行的数据信息。 而错误的输出还是会输出到屏幕,很多时候我们更关注错误的输出,所以也需要将标准错误输出重定向到文件,可以将这两种信息分流输出到不同的文件:
              [peter@study ~]$ find /home -name .bashrc > rightfile 2> errorfile
            
此时屏幕上就不会有任何输出信息了!因为刚刚执行的结果中, 带Permission denied的那几行错误信息就会输出到errorfile文件,而正确的输出数据则会存到rightfile文件中!

上面我们都是将标准输出和标准错误输出分流输出到不同的文件中了,那么如何将所有的输出信息重定向到一个文件呢?
按照上面的写法我们很容易就会想到下面这样的写法:

              #错误写法
              [peter@study ~]$ find /home -name .bashrc > list 2> list
            
上面的写法是错误的。由于两股数据流同时写入同一个文件,而又没有使用特殊的语法,此时两股数据可能会交叉写入该文件内,造成次序的混乱。
虽然最终还是会产生list文件,但是文件中的内容顺序可能是乱的,而不是原本屏幕上的输出排序。
正确的写法是使用2>&1或者&>,如下所示:
              [peter@study ~]$ find /home -name .bashrc > list 2>&1
              [peter@study ~]$ find /home -name .bashrc &> list
            
推荐使用2>&1的语法!

垃圾桶黑洞设备/dev/null与特殊写法

回到顶部

有时候我们并不关心命令的输出结果,为了不影响屏幕,我们会将命令的输出重定向到一个特殊的设备,这就是黑洞设备/dev/null。 所有写入该设备的数据都会消失不见。
例如上面的例子,我们将标准错误输出到/dev/null:

              [peter@study ~]$ find /home -name .bashrc 2> /dev/null
              /home/peter/.bashrc
            
这样屏幕上就只会出现正确的stdout输出信息,而错误的stderr输出信息被彻底丢弃了!

那么为何要使用命令输出重定向呢?我们来说一说吧!

屏幕输出的信息很重要,需要存下来;
后台执行中的程序,不希望他干扰屏幕正常的输出结果;
一些系统的例行命令(例如写在/etc/crontab中的文件)的执行结果,希望可以存下来;
一些执行命令的可能已知错误讯息时,想以2> /dev/null丢弃掉;
错误讯息与正确讯息需要分别输出。
假设我要将echo "error message"以standard error output的格式来输出,该如何处置?
既然2>&1可以将2>转到1>,那么应该也会有1>&2,因此可以这样:
              [peter@study ~]$ echo "error message" 1>&2
              [peter@study ~]$ echo "error message" 2> /dev/null 1>&2
            
你会发现第一条有讯息输出到屏幕上,第二条则没有讯息!这表示该讯息已经是透过2> /dev/null丢到垃圾桶去了,可以肯定是错误讯息啰!

标准输入standard input重定向: <与<<

回到顶部

标准输出和标准错误输出默认都是输出到屏幕设备,而标准输入设备默认是键盘。 输出重定向>和>>是将原本输出到屏幕的数据输出到指定的文件或者设备中。
同样的道理,输入重定向<与<<就是将原本由标准输入设备(键盘)输入的数据,改为由指定的文件输入。
例如cat命令,如果不加文件参数的话,默认就是读取标准输入,然后输出到标准输出。

              [peter@study ~]$ cat
              haha
              haha
              this is a cat testing
              this is a cat testing
            
如果只执行cat命令,cat就会等待用户输入,用户按下enter键,cat就会将用户输入的信息输出到屏幕上。

我们可以用输出重定向将输出重定向到一个文件,这样就相当于在命令行下直接创建文件并且写入文件内容了:

              [peter@study ~]$ cat > catfile
              testing
              cat file test
            
按下ctrl+d结束输入,查看catfile文件的内容:
              [peter@study ~]$ cat catfile
              testing
              cat file test
            
刚才我们是通过键盘输入的方式,将数据输入给cat,然后cat再将数据输出到catfile文件。

输入重定向<可以用纯文本文件取代键盘的输入。如下用~/.bashrc取代键盘的输入以建立新文件的简单流程:

              [peter@study ~]$ cat > catfile < ~/.bashrc
              [peter@study ~]$ ls -l catfile ~/.bashrc
              -rw-r--r--. 1 peter peter 231 Mar 6 06:06 /home/peter/.bashrc
              -rw-rw-r--. 1 peter peter 231 Jul 9 18:58 catfile
            
这两个文件的大小一模一样!几乎像是用cp复制的一样!
而<<两个连续小于符号指定结束输入的关键字符。 例如用cat将输入的信息输出到catfile文件, 指定当键盘输入eof时,结束输入:
              [peter@study ~]$ cat > catfile << "eof"
              > This is a test.
              > OK now stop
              > eof
              [peter@study ~]$ cat catfile
              This is a test.
              OK now stop
              #只有这两行,不会存在关键词那一行!
            
输入关键词eof, 立刻结束输入。利用<<右侧的控制字符,可以终止一次输入, 而不需要输入crtl+d!

本文由initroot编辑整理,转载请注明www.initroot.com