注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

谷搜互联网应用www.iguso.com

谷搜专注企业邮箱十二年

 
 
 

日志

 
 

资料流重导向(redirect)  

2014-05-29 15:44:43|  分类: 技术文章 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

资料流重导向 (redirect) 由字面上的意思来看,好像就是将『资料给他传导到其他地方去』的样子? 没错~资料流重导向就是将某个指令执行后应该要出现在屏幕上的资料, 给他传输到其他的地方,例如档案或者是装置 (例如印表机之类的)!这玩意儿在 Linux 的文字模式底下可重要的! 尤其是如果我们想要将某些资料储存下来时,就更有用了!

  什么是资料流重导向

  什么是资料流重导向啊?这得要由指令的执行结果谈起!一般来说,如果你要执行一个指令,通常他会是这样的:

  


 

  图 5.1.1、指令执行过程的资料传输情况

  我们执行一个指令的时候,这个指令可能会由档案读入资料,经过处理之后,再将资料输出到萤幕上。 在上图当中, standard output 与 standard error output 分别代表『标準输出』与『标準错误输出』, 这两个玩意儿预设都是输出到萤幕上面来的啊!那么什么是标準输出与标準错误输出呢?

  standard output 与 standard error output

  简单的说,标準输出指的是『指令执行所回传的正确的讯息』,而标準错误输出可理解为『 指令执行失败后,所回传的错误讯息』。举个简单例子来说,我们的系统预设有 /etc/crontab 但却无 /etc/vbirdsay, 此时若下达『 cat /etc/crontab /etc/vbirdsay 』这个指令时,cat 会进行:

  标準输出:读取 /etc/crontab 后,将该档案内容显示到萤幕上;

  标準错误输出:因为无法找到 /etc/vbirdsay,因此在萤幕上显示错误讯息

  不管正确或错误的资料都是预设输出到萤幕上,所以萤幕当然是乱乱的!那能不能透过某些机制将这两股资料分开呢? 当然可以啊!那就是资料流重导向的功能啊!资料流重导向可以将 standard output (简称 stdout) 与 standard error output (简称 stderr) 分别传送到其他的档案或装置去,而分别传送所用的特殊字元则如下所示:

  标準输入  (stdin) :代码为 0 ,使用 < 或 << ;

  标準输出  (stdout):代码为 1 ,使用 > 或 >> ;

  标準错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;

  为了理解 stdout 与 stderr ,我们先来进行一个範例的练习:

  範例一:观察你的系统根目录 (/) 下各目录的档名、权限与属性,并记录下来

  [root@www ~]# ll / <==此时萤幕会显示出档名资讯

  [root@www ~]# ll / > ~/rootfile <==萤幕并无任何资讯

  [root@www ~]# ll ~/rootfile <==有个新档被建立了!

  -rw-r--r-- 1 root root 1089 Feb 6 17:00 /root/rootfile

  怪了!萤幕怎么会完全没有资料呢?这是因为塬本『 ll / 』所显示的资料已经被重新导向到 ~/rootfile 档案中了! 那个 ~/rootfile 的档名可以随便你取。如果你下达『 cat ~/rootfile 』那就可以看到塬本应该在萤幕上面的资料啰。 如果我再次下达:『 ll /home > ~/rootfile 』后,那个 ~/rootfile 档案的内容变成什么? 他将变成『仅有 ll /home 的资料』而已!咦!塬本的『 ll / 』资料就不见了吗?是的!因为该档案的建立方式是:

  该档案 (本例中是 ~/rootfile) 若不存在,系统会自动的将他建立起来,但是

  当这个档案存在的时候,那么系统就会先将这个档案内容清空,然后再将资料写入!

  也就是若以 > 输出到一个已存在的档案中,那个档案就会被覆盖掉啰!

  那如果我想要将资料累加而不想要将旧的资料删除,那该如何是好?利用两个大于的符号 (>>) 就好啦!以上面的範例来说,你应该要改成『 ll / >> ~/rootfile 』即可。 如此一来,当 (1) ~/rootfile 不存在时系统会主动建立这个档案;(2)若该档案已存在, 则资料会在该档案的最下方累加进去!

  上面谈到的是 standard output 的正确资料,那如果是 standard error output 的错误资料呢?那就透过 2> 及 2>> 啰!同样是覆盖 (2>) 与累加 (2>>) 的特性!我们在刚刚才谈到 stdout 代码是 1 而 stderr 代码是 2 , 所以这个 2> 是很容易理解的,而如果仅存在 > 时,则代表预设的代码 1 啰!也就是说:

  1> :以覆盖的方法将『正确的资料』输出到指定的档案或装置上;

  1>>:以累加的方法将『正确的资料』输出到指定的档案或装置上;

  2> :以覆盖的方法将『错误的资料』输出到指定的档案或装置上;

  2>>:以累加的方法将『错误的资料』输出到指定的档案或装置上;

  要注意喔,『 1>> 』以及『 2>> 』中间是没有空格的!OK!有些概念之后让我们继续聊一聊这傢伙怎么应用吧! 当你以一般身份执行 find 这个指令的时候,由于权限的问题可能会产生一些错误资讯。例如执行『 find / -name testing 』时,可能会产生类似『 find: /root: Permission denied 』之类的讯息。 例如底下这个範例:

  範例二:利用一般身份帐号搜寻 /home 底下是否有名为 .bashrc 的档案存在

  [root@www ~]# su - dmtsai <==假设我的系统有名为 dmtsai 的帐号

  [dmtsai@www ~]$ find /home -name .bashrc <==身份是 dmtsai 喔!

  find: /home/lost+found: Permission denied <== Standard error

  find: /home/alex: Permission denied <== Standard error

  find: /home/arod: Permission denied <== Standard error

  /home/dmtsai/.bashrc <== Standard output

  由于 /home 底下还有我们之前建立的帐号存在,那些帐号的家目录你当然不能进入啊!所以就会有错误及正确资料了。 好了,那么假如我想要将资料输出到 list 这个档案中呢?执行『 find /home -name .bashrc > list 』 会有什么结果?嗬嗬,你会发现 list 裡面存了刚刚那个『正确』的输出资料, 至于萤幕上还是会有错误的讯息出现呢!伤脑筋!如果想要将正确的与错误的资料分别存入不同的档案中需要怎么做?

  範例叁:承範例二,将 stdout 与 stderr 分存到不同的档案去

  [dmtsai@www ~]$ find /home -name .bashrc > list_right 2> list_error

  注意喔,此时『萤幕上不会出现任何讯息』!因为刚刚执行的结果中,有 Permission 的那几行错误资讯都会跑到 list_error 这个档案中,至于正确的输出资料则会存到 list_right 这个档案中啰!这样可以瞭解了吗? 如果有点混乱的话,去休息一下再来看看吧!

  /dev/null 垃圾桶黑洞装置与特殊写法

  想像一下,如果我知道错误讯息会发生,所以要将错误讯息忽略掉而不显示或储存呢? 这个时候黑洞装置 /dev/null 就很重要了!这个 /dev/null 可以吃掉任何导向这个装置的资讯喔!将上述的範例修订一下:

  範例四:承範例叁,将错误的资料丢弃,萤幕上显示正确的资料

  [dmtsai@www ~]$ find /home -name .bashrc 2> /dev/null

  /home/dmtsai/.bashrc <==只有 stdout 会显示到萤幕上, stderr 被丢弃了

  再想像一下,如果我要将正确与错误资料通通写入同一个档案去呢?这个时候就得要使用特殊的写法了! 我们同样用底下的案例来说明:

  範例五:将指令的资料全部写入名为 list 的档案中

  [dmtsai@www ~]$ find /home -name .bashrc > list 2> list <==错误

  [dmtsai@www ~]$ find /home -name .bashrc > list 2>&1 <==正确

  [dmtsai@www ~]$ find /home -name .bashrc &> list <==正确

  上述表格第一行错误的塬因是,由于两股资料同时写入一个档案,又没有使用特殊的语法, 此时两股资料可能会交叉写入该档案内,造成次序的错乱。所以虽然最终 list 档案还是会产生,但是裡面的资料排列就会怪怪的,而不是塬本萤幕上的输出排序。 至于写入同一个档案的特殊语法如上表所示,你可以使用 2>&1 也可以使用 &> ! 一般来说,鸟哥比较习惯使用 2>&1 的语法啦!

  standard input : < 与 <<

  瞭解了 stderr 与 stdout 后,那么那个 < 又是什么呀?嗬嗬!以最简单的说法来说, 那就是『将塬本需要由键盘输入的资料,改由档案内容来取代』的意思。 我们先由底下的 cat 指令操作来瞭解一下什么叫做『键盘输入』吧!

  範例六:利用 cat 指令来建立一个档案的简单流程

  [root@www ~]# cat > catfile

  testing

  cat file test

  <==这裡按下 [ctrl]+d 来离开

  [root@www ~]# cat catfile

  testing

  cat file test

  由于加入 > 在 cat 后,所以那个 catfile 会被主动的建立,而内容就是刚刚键盘上面输入的那两行资料了。 唔!那我能不能用纯文字档取代键盘的输入,也就是说,用某个档案的内容来取代键盘的敲击呢? 可以的!如下所示:

  範例七:用 stdin 取代键盘的输入以建立新档案的简单流程

  [root@www ~]# cat > catfile < ~/.bashrc

  [root@www ~]# ll catfile ~/.bashrc

  -rw-r--r-- 1 root root 194 Sep 26 13:36 /root/.bashrc

  -rw-r--r-- 1 root root 194 Feb 6 18:29 catfile

  # 注意看,这两个档案的大小会一模一样!几乎像是使用 cp 来复製一般!

  这东西非常的有帮助!尤其是用在类似 mail 这种指令的使用上。 理解 < 之后,再来则是怪可怕一把的 << 这个连续两个小于的符号了。 他代表的是『结束的输入字元』的意思!举例来讲:『我要用 cat 直接将输入的讯息输出到 catfile 中, 且当由键盘输入 eof 时,该次输入就结束』,那我可以这样做:

  [root@www ~]# cat > catfile << "eof"

  > This is a test.

  > OK now stop

  > eof <==输入这关键字,立刻就结束而不需要输入 [ctrl]+d

  [root@www ~]# cat catfile

  This is a test.

  OK now stop <==只有这两行,不会存在关键字那一行!

  看到了吗?利用 << 右侧的控制字元,我们可以终止一次输入, 而不必输入 [crtl]+d 来结束哩!这对程式写作很有帮助喔!好了,那么为何要使用命令输出重导向呢?我们来说一说吧!

  萤幕输出的资讯很重要,而且我们需要将他存下来的时候;

  背景执行中的程式,不希望他干扰萤幕正常的输出结果时;

  一些系统的例行命令 (例如写在 /etc/crontab 中的档案) 的执行结果,希望他可以存下来时;

  一些执行命令的可能已知错误讯息时,想以『 2> /dev/null 』将他丢掉时;

  错误讯息与正确讯息需要分别输出时。

  当然还有很多的功能的,最简单的就是网友们常常问到的:『为何我的 root 都会收到系统 crontab 寄来的错误讯息呢』这个咚咚是常见的错误, 而如果我们已经知道这个错误讯息是可以忽略的时候,嗯!『 2> errorfile 』这个功能就很重要了吧! 瞭解了吗?

  命令执行的判断依据: ; , &&, ||

  在某些情况下,很多指令我想要一次输入去执行,而不想要分次执行时,该如何是好?基本上你有两个选择, 一个是透过第十叁章要介绍的 shell script 撰写脚本去执行,一种则是透过底下的介绍来一次输入多重指令喔!

  cmd ; cmd (不考虑指令相关性的连续指令下达)

  在某些时候,我们希望可以一次执行多个指令,例如在关机的时候我希望可以先执行两次 sync 同步化写入磁碟后才 shutdown 电脑,那么可以怎么作呢?这样做呀:

  [root@www ~]# sync; sync; shutdown -h now

  在指令与指令中间利用分号 (;) 来隔开,这样一来,分号前的指令执行完后就会立刻接着执行后面的指令了。 这真是方便啊~再来,换个角度来想,万一我想要在某个目录底下建立一个档案,也就是说,如果该目录存在的话, 那我才建立这个档案,如果不存在,那就算了。也就是说这两个指令彼此之间是有相关性的, 前一个指令是否成功的执行与后一个指令是否要执行有关!那就得动用到 && 或 || 啰!

  $? (指令回传值) 与 && 或 ||

  如同上面谈到的,两个指令之间有相依性,而这个相依性主要判断的地方就在于前一个指令执行的结果是否正确。 还记得本章之前我们曾介绍过指令回传值吧!嘿嘿!没错,您真聪明!就是透过这个回传值啦! 再复习一次『若前一个指令执行的结果为正确,在 Linux 底下会回传一个 $? = 0 的值』。 那么我们怎么透过这个回传值来判断后续的指令是否要执行呢?这就得要藉由『 && 』及『 || 』的帮忙了! 注意喔,两个 & 之间是没有空格的!那个 | 则是 [Shift]+[\] 的按键结果。

  指令下达情况说明

  cmd1 && cmd21. 若 cmd1 执行完毕且正确执行($?=0),则开始执行 cmd2。

  2. 若 cmd1 执行完毕且为错误 ($?≠0),则 cmd2 不执行。

  cmd1 || cmd21. 若 cmd1 执行完毕且正确执行($?=0),则 cmd2 不执行。

  2. 若 cmd1 执行完毕且为错误 ($?≠0),则开始执行 cmd2。企业邮箱

  上述的 cmd1 及 cmd2 都是指令。好了,回到我们刚刚假想的情况,就是想要: (1)先判断一个目录是否存在; (2)若存在才在该目录底下建立一个档案。由于我们尚未介绍如何判断式 (test) 的使用,在这裡我们使用 ls 以及回传值来判断目录是否存在啦! 让我们进行底下这个练习看看:

  範例一:使用 ls 查阅目录 /tmp/abc 是否存在,若存在则用 touch 建立 /tmp/abc/hehe

  [root@www ~]# ls /tmp/abc && touch /tmp/abc/hehe

  ls: /tmp/abc: No such file or directory

  # ls 很乾脆的说明找不到该目录,但并没有 touch 的错误,表示 touch 并没有执行

  [root@www ~]# mkdir /tmp/abc

  [root@www ~]# ls /tmp/abc && touch /tmp/abc/hehe

  [root@www ~]# ll /tmp/abc

  -rw-r--r-- 1 root root 0 Feb 7 12:43 hehe

  看到了吧?如果 /tmp/abc 不存在时,touch 就不会被执行,若 /tmp/abc 存在的话,那么 touch 就会开始执行啰! 很不错用吧!不过,我们还得手动自行建立目录,伤脑筋~能不能自动判断,如果没有该目录就给予建立呢? 参考一下底下的例子先:

  範例二:测试 /tmp/abc 是否存在,若不存在则予以建立,若存在就不作任何事情

  [root@www ~]# rm -r /tmp/abc <==先删除此目录以方便测试

  [root@www ~]# ls /tmp/abc || mkdir /tmp/abc

  ls: /tmp/abc: No such file or directory <==真的不存在喔!

  [root@www ~]# ll /tmp/abc

  total 0 <==结果出现了!有进行 mkdir

  如果你一再重复『 ls /tmp/abc || mkdir /tmp/abc 』画面也不会出现重复 mkdir 的错误!这是因为 /tmp/abc 已经存在, 所以后续的 mkdir 就不会进行!这样理解否?好了,让我们再次的讨论一下,如果我想要建立 /tmp/abc/hehe 这个档案, 但我并不知道 /tmp/abc 是否存在,那该如何是好?试看看:

  範例叁:我不清楚 /tmp/abc 是否存在,但就是要建立 /tmp/abc/hehe 档案

  [root@www ~]# ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe

  上面这个範例叁总是会建立 /tmp/abc/hehe 的喔!不论 /tmp/abc 是否存在。那么範例叁应该如何解释呢? 由于Linux 底下的指令都是由左往右执行的,所以範例叁有几种结果我们来分析一下:

  (1)若 /tmp/abc 不存在故回传 $?≠0,则 (2)因为 || 遇到非为 0 的 $? 故开始 mkdir /tmp/abc,由于 mkdir /tmp/abc 会成功进行,所以回传 $?=0 (3)因为 && 遇到 $?=0 故会执行 touch /tmp/abc/hehe,最终 hehe 就被建立了;

  (1)若 /tmp/abc 存在故回传 $?=0,则 (2)因为 || 遇到 0 的 $? 不会进行,此时 $?=0 继续向后传,故 (3)因为 && 遇到 $?=0 就开始建立 /tmp/abc/hehe 了!最终 /tmp/abc/hehe 被建立起来。数据库空间

  整个流程图示如下:

  


 

  图 5.2.1、 指令依序执行的关係示意图

  上面这张图显示的两股资料中,上方的线段为不存在 /tmp/abc 时所进行的指令行为,下方的线段则是存在 /tmp/abc 所在的指令行为。如上所述,下方线段由于存在 /tmp/abc 所以导致 $?=0 ,让中间的 mkdir 就不执行了! 并将 $?=0 继续往后传给后续的 touch 去利用啦!瞭乎?在任何时刻你都可以拿上面这张图作为示意! 让我们来想想底下这个例题吧!

  例题:

  以 ls 测试 /tmp/vbirding 是否存在,若存在则显示 "exist" ,若不存在,则显示 "not exist"!

  答:

  这又牵涉到逻辑判断的问题,如果存在就显示某个资料,若不存在就显示其他资料,那我可以这样做:

  ls /tmp/vbirding && echo "exist" || echo "not exist"

  意思是说,当 ls /tmp/vbirding 执行后,若正确,就执行 echo "exist" ,若有问题,就执行 echo "not exist" !那如果写成如下的状况会出现什么?

  ls /tmp/vbirding || echo "not exist" && echo "exist"

  这其实是有问题的,为什么呢?由图 5.2.1 的流程介绍我们知道指令是一个一个往后执行, 因此在上面的例子当中,如果 /tmp/vbirding 不存在时,他会进行如下动作:

  若 ls /tmp/vbirding 不存在,因此回传一个非为 0 的数值;

  接下来经过 || 的判断,发现前一个指令回传非为 0 的数值,因此,程式开始执行 echo "not exist" ,而 echo "not exist" 程式肯定可以执行成功,因此会回传一个 0 值给后面的指令;

  经过 && 的判断,咦!是 0 啊!所以就开始执行 echo "exist" 。

  所以啊,嘿嘿!第二个例子裡面竟然会同时出现 not exist 与 exist 呢!真神奇~

  经过这个例题的练习,你应该会瞭解,由于指令是一个接着一个去执行的,因此,如果真要使用判断, 那么这个 && 与 || 的顺序就不能搞错。一般来说,假设判断式有叁个,也就是:

  command1 && command2 || command3

  而且顺序通常不会变,因为一般来说, command2 与 command3 会放置肯定可以执行成功的指令, 因此,依据上面例题的逻辑分析,您就会晓得为何要如此放置啰~这很有用的啦!而且.....考试也很常考~


文章源自谷搜服务商 资料流重导向(redirect)
  评论这张
 
阅读(9)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017