数据流重导向[转]
2015-12-18 12:16
218 查看
数据流重导向
数据流重导向 (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 |
该文件 (本例中是 ~/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 |
范例三:承范例二,将 stdout 与 stderr 分存到不同的文件去 [dmtsai@www ~]$ find /home -name .bashrc > list_right 2> list_error |
/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 <==正确 |
standard input : < 与 <<
了解了 stderr 与 stdout 后,那么那个 < 又是什么呀?呵呵!以最简单的说法来说, 那就是『将原本需要由键盘输入的数据,改由文件内容来取代』的意思。 我们先由底下的 cat 命令操作来了解一下什么叫做『键盘输入』吧!
范例六:利用 cat 命令来创建一个文件的简单流程 [root@www ~]# cat > catfile testing cat file test <==这里按下 [ctrl]+d 来离开 [root@www ~]# cat catfile testing cat file test |
范例七:用 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 来复制一般! |
[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 <==只有这两行,不会存在关键词那一行! |
屏幕输出的信息很重要,而且我们需要将他存下来的时候;
背景运行中的程序,不希望他干扰屏幕正常的输出结果时;
一些系统的例行命令 (例如写在 /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 && cmd2 | 1. 若 cmd1 运行完毕且正确运行($?=0),则开始运行 cmd2。 2. 若 cmd1 运行完毕且为错误 ($?≠0),则 cmd2 不运行。 |
cmd1 || cmd2 | 1. 若 cmd1 运行完毕且正确运行($?=0),则 cmd2 不运行。 2. 若 cmd1 运行完毕且为错误 ($?≠0),则开始运行 cmd2。 |
范例一:使用 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 是否存在,若不存在则予以创建,若存在就不作任何事情 [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 |
范例三:我不清楚 /tmp/abc 是否存在,但就是要创建 /tmp/abc/hehe 文件 [root@www ~]# ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe |
(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 会放置肯定可以运行成功的命令, 因此,依据上面例题的逻辑分析,您就会晓得为何要如此放置啰~这很有用的啦!而且.....考试也很常考~
相关文章推荐
- 需求 - 15 - "带下划线"
- 用vs打开更高版本的工程(如VS2010打开VS2012的工程)
- 黑马程序员——Java---异常
- 微信公众平台下载多媒体文件
- 数据结构实验 第二单元 汉诺塔(非递归,用栈模拟递归)
- 数据结构实验 第二单元 汉诺塔(非递归,用栈模拟递归)
- C /C++标准库 - <cstddef> (stddef.h)
- 数据结构实验 第二单元 括号匹配
- 数据结构实验 第二单元 括号匹配
- SQL Server UDF用户自定义函数
- 黑马程序员 - OC语言 - 【考点】分类(Category)使用注意事项
- jquery简单倒计时实现方法
- 前序遍历和中序遍历序列能确定唯一的一棵二叉树
- 数据结构实验 第二单元 栈操作
- 数据结构实验 第二单元 栈操作
- 黑马程序员 - OC语言 - 构造方法的概念
- 102,block的基本使用
- Android GreenDao使用详解
- SharePoint : 使用SPQuery对象时要注意的事项
- ApplicationContext接口的继承关系