linux数据流重定向


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

什么是数据流重定向

回到顶部
说到数据流重定向功能,就得了解命令的标准输入、标准输出和标准错误输出。一般来说,一条命令的数据传输如下图所示:
linux命令数据传输 图 命令执行过程的数据传输
一条命令可以由标准输入读入数据,经过处理后再由标准输出standard output输出到屏幕,如果命令执行过程出现错误, 也会通过标准错误输出standard error output到屏幕。
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 ,使用 > 或 >>表示 ;
3. 标准错误输出(stderr): 代码为 2 ,使用 2> 或 2>>表示 ;
为了理解 stdout 与 stderr ,我们先来进行一个范例的练习:
范例一:观察你的系统根目录 (/) 下各目录的文件名、权限与属性,并记录下来
我们用ls -al /查看根目录下的文件信息,并将输出重定向到rootfile文件中:
[peter@study ~]$ ls -al / > ~/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文件只有ls -al /home的输出数据,之前的内容被覆盖掉了! 数据流重定向>输出数据到文件的方式为:
1. 若文件不存在,自动创建该文件。
2. 如果文件存在,那么先将文件内容清空,然后再写入数据!
也就是说>会覆盖掉文件原本的内容。
但是很多时候我们还是希望保留文件原本的内容,只是将新数据追加到文件的末尾即可。这时候就将>换成>>就可以了。 上面改成ls -al /home >> ~/rootfile即可。
>>输出数据到文件的方式为:
1. 如果文件不存在,自动创建文件;
2. 如果文件已存在, 将输出数据追加到文件末尾!
>和>>默认重定向标准输出,如果需要将standard error output重定向,就需要用到2>和2>>! 和>/>>类似,2>将输出覆盖文件而2>>将输出追加到文件。我们在刚刚才提到stdout代码是1, 而stderr代码是2, 所以这个2>就是重定向标准错误输出,而如果仅是> 时,则代表默认的代码为1!
也就是说:
>或1> :以覆盖的方式将标准输出数据输出到指定文件或者设备;
>>或1>>:以累加的方式将标准输出数据输出到指定的文件或设备;
2> :以覆盖的方式将标准错误输出数据输出到指定文件或者设备;
2>>:以累加的方式将标准错误输出数据输出到指定的文件或设备;
注意1>>或2>>中间是没有空格的! 一般普通用户执行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 > list_right 2> list_error
此时屏幕上就不会有任何输出信息了!因为刚刚执行的结果中, 带Permission denied的那几行错误信息就会输出到list_error文件, 而正确的输出数据则会存到list_right文件中!

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

回到顶部
有时候我们并不关心命令的输出结果,为了不影响屏幕,我们会将命令的输出重定向到一个特殊的设备, 这就是黑洞设备/dev/null。所有写入该设备的数据都会消失不见,烟消云散。
例如上面的例子,我们将标准错误输出到/dev/null:
[peter@study ~]$ find /home -name .bashrc 2> /dev/null
/home/peter/.bashrc
这样屏幕上就只会出现正确的stdout输出信息,而错误的stderr输出信息被彻底丢弃了,想找也找不回来了!
上面我们都是将标准输出和标准错误输出分流输出到不同的文件中了,那么如何将所有的输出信息重定向到一个文件中呢?
按照上面的写法我们很容易就会想到下面这样的写法:
[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的语法!
那么为何要使用命令输出重定向呢?我们来说一说吧!
屏幕输出的信息很重要,而且我们需要将他存下来的时候;
背景执行中的程序,不希望他干扰屏幕正常的输出结果时;
一些系统的例行命令 (例如写在 /etc/crontab 中的文件) 的执行结果,希望他可以存下来时;
一些执行命令的可能已知错误讯息时,想以2> /dev/null将他丢掉时;
错误讯息与正确讯息需要分别输出时。
当然还有很多的功能的,最简单的就是网友们常常问到的:
为何我的 root 都会收到系统 crontab 寄来的错误讯息呢』这个咚咚是常见的错误, 而如果我们已经知道这个错误讯息是可以忽略的时候, 嗯!『 2> errorfile 』这个功能就很重要了吧! 了解了吗?
假设我要将 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命令,如果不加文件参数的话,默认就是读取标准输入,然后输出到标准输出。
可以在命令行输入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结束输入并离开cat。然后我们查看一下catfile文件的内容:
[peter@study ~]$ cat catfile
testing
cat file test
刚才我们是通过键盘输入的方式,将数据输入给cat,然后cat再讲数据输出到catfile文件。能不能用纯文本文件取代键盘的输入呢? 也就是用某个文件的内容来取代键盘的敲击呢? 如下所示:
用 stdin 取代键盘的输入以建立新文件的简单流程
[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来复制一般!
这东西非常的有帮助!尤其是用在类似 mail 这种指令的使用上。 理解 < 之后,再来则是怪可怕一 把的 << 这个连续两个小于的符号了。 他代表的是『结束的输入字符』的意思!举例来讲:『我要 用 cat 直接将输入的讯息输出到 catfile 中, 且当由键盘输入 eof 时,该次输入就结束』,那我可 以这样做:
[peter@study ~]$ cat > catfile << "eof"
> This is a test.
> OK now stop
> eof
输入这关键词eof, 立刻就结束而不需要输入ctrl+d
[peter@study ~]$ cat catfile
This is a test.
OK now stop
只有这两行,不会存在关键词那一行! 利用 << 右侧的控制字符,我们可以终止一次输入, 而不必输入 [crtl]+d 来结束! 这对程序写作很有帮助喔!

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

100次点赞 100次阅读