数据流重定向

数据流重导向就是将某个指令执行后应该要出现在屏幕上的数据, 给他传输到其它的地方,例如档案或者是装置 (例如打印机之类的!)!这玩意儿在 Linux 的文字模式底下可重要的! 尤其是如果我们想要将某些数据储存下来时,就更有用了!

一般来说,如果你要执行一个指令,通常他会是这样的:

我们执行一个指令的时候,这个指令可能会由档案读入资料,经过处理之后,再将数据输出到屏幕上。 在图中, standard output 与 standard error 分别代表标准输出与标准错误输出, 这两个玩意儿预设都是输出到屏幕上面来的啊!举个简单例子来说, 我们下达『 cat /etc/crontab /etc/vbirdsay 』这个指令时,cat 会由 /etc/crontab 与 /etc/vbirdsay 读入数据, 然后再将数据输出到屏幕上,不过,因为系统本来就不存在
/etc/vbirdsay 这个档案, 所以就会显示错误讯息,这个错误讯息也会输出到屏幕上来喔! 在这样的过程当中,我们可以将 standard error (简称 stderr) 与 standard output (简称 stdout) 给他传送到其它不同的地方,而不是屏幕上头!传送的目标处,通常是档案或者是装置! 而传送的指令则是如下所示:

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

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

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



举例来说,如果我想要将我目前根目录下所有的目录都记录下来的话,也就是说,将 ls -l / 这个指令的输出结果储存下来,就可以:

[root@linux ~]# ls -l / > ~/rootfile

# 本来 ls -l / 会将根目录的数据列出到屏幕上;

# 现在我使用了 > ~/rootfile 后,则本来应该在屏幕上出现的数据

# 就会被『重新导向』到 ~/rootfile 档案内了!就可以将该数据储存!



此时,原本应该在屏幕上面出现的数据通通不见去~因为那些资料都被写入到 ~/rootfile 去了! 当然,那个档案的档名随便你取啦~如果你下达:『 cat ~/rootfile 』就可以看到原本应该在屏幕上面的数据啰。 那么如果我再次下达:『 ls -l /home > ~/rootfile 』后,那么那个 ~/rootfile 档案的内容变成什么? 呵呵!变成『仅有 ls -l /home 的数据』而已!咦!原本的 ls -l /
数据就不见了吗?是的! 因为该档案的建立方式是:

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

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

3. 也就是若以 > 输出到一个既存盘案中,呵呵,那个档案就会被覆盖掉啰!



那如果我想要将数据累加,不想要将旧的数据删除,那该如何是好? 呵呵!就利用 >> 就好啦!例如上面的例子中,就变成『ls -l / >> ~/rootfile』 如此一来,当 ~/rootfile 不存在时,系统会主动建立这个档案,若该档案已存在, 则数据会在该档案的最下方累加进去!基本上,指令的下达方式:

command  > 1> 2> 2>> <  装置或档案



当然啦,一串指令的最左边一定是指令,而在 >,2>,< 右边的,必须是档案或装置才行! 此外,那个 > 会等于 1> ,因为 standard output 代码是 1 ,可以省略啦! 再者, 1 与 > 之间并没有空格喔!是紧接在一起的!注意注意!我们底下来玩几个东西好了:



范例一:将目前目录下的档案信息全部储存到 list.txt 档案中

[root@linux ~]# ls -al > list.txt

范例二:将根目录下的数据也储存到 list.txt 档案中

[root@linux ~]# ls -al / >> list.txt



好了,对于『 > , >> 』这两个东西有一定的概念之后,我们来深入的谈一谈『数据流重导向』的观念吧! 如前所述,基本上, Linux 执行的结果中,可以约略的分成『正确输出』与『错误输出』两种数据。 例如,当你以一般身份执行 find 这个指令时,例如执行『 find / -name testing 』时,由于你是一般身份,又有些数据夹是不允许一般身份者进入的,
所以啰,当你使用 find 时,就会有错误讯息发生了!但同时如果有 testing 这个档案在你可以进入的资料夹当中,那么屏幕也会输出到给你看!因此, 就具有正确的与错误的输出两种啰!(分别称为 Stdout 与 Stderror)例如下面为执行结果: 里面的『 find: /home/root: Permission denied 』就告诉你该数据夹你没有权限进入, 这就是错误的输出了,那么『 /home/dmtsai/tseting 』就是正确的输出了!



[dmtsai@linux ~]$ find /home -name testing

find: /home/test1: Permission denied <== Starndard error

find: /home/root: Permission denied <== Starndard error

find: /home/masda: Permission denied <== Starndard error

/home/dmtsai/testing <== Starndard output



好了,那么假如我们想要将数据输出到 list 这个档案中呢?执行『 find / -name testing > list 』 会有什么结果?呵呵,你会发现 list 里面存了刚刚那个『正确』的输出数据, 至于屏幕上还是会有错误的讯息出现呢!伤脑筋!如果想要将正确的与错误的数据分别存入不同的档案中需要怎么做?! 呵呵!其实在数据的重导向方面,正确的写法应该是『 1> 』与『 2> 』才对!但是如果只有 > 则预设是以 1> 来进行数据的!那个
1> 是输出正确数据, 2> 则是错误数据输出项目。也就说:

1> :是将正确的数据输出到指定的地方去

2> :是将错误的数据输出到指定的地方去



好了,那么上面的例子中,我们如何将数据输出到不同的地方去呢?可以这么写:

[dmtsai@linux ~]$ find /home -name testing > list_right 2> list_error



这样一来,刚刚执行的结果中,有 Permission 的那几行错误信息都会跑到 list_error 这个档案中,至于正确的输出数据则会存到 list_right 这个档案中啰!这样可以了解了吗? 如果有点混乱的话,去休息一下再来看看吧!! 再来,如果我只要正确的数据,错误的信息我不要了呢?呵呵,这个时候 /dev/null 这个垃圾桶就很重要了!/dev/null
是什么呢? 基本上,那就有点像是一个『黑洞』的垃圾桶功能!当你输入的任何东西导向到这个虚拟的垃圾桶装置时, 『他就会凭空消失不见了~~』,这个东西有用的很!例如上面的例子中,我们可以这么做,来将错误的信息丢掉!



[dmtsai@linux ~]$ find /home -name testing > list_right 2> /dev/null

很神奇呦! error message 就会『不见了!』呵呵!真高兴!另外, 如果我要将数据都写到同一个档案中呢?这个时候写法需要用到特殊写法,请注意底下的写法呦!



[dmtsai@linux ~]$ find /home -name testing > list 2> list <==错误写法

[dmtsai@linux ~]$ find /home -name testing > list 2>&1 <==正确写法



请特别留意这一点呢!同时写入同一个档案需要使用 2>&1 才对呦! OK!了解了 >, 2>, >> 与 /dev/null 之后,那么那个 < 又是什么呀!?呵呵!以最简单的说法来说, 那就是『将原本需要由键盘输入的数据,经由档案来读入』的意思。 举例来说,我们可以使用 cat 在键盘上面输入一些数据,然后写入一个档案内,例如:

[root@linux ~]# cat > catfile

testing

cat file test

<==这里按下 [ctrl]+d 结束输入来离开!



此时就会有 catfile 这个档案产生,而且该档案的内容就是刚刚输入的内容喔。 那么,我是否可以使用其它档案来取代键盘输入呢?可以啊!这样做!

[root@linux ~]# cat > catfile < somefile



我可以先编辑 somefile ,然后再以上述的指令来将数据输出到 catfile 去呢!这样可以理解了吗? 能够理解 < 之后,再来则是怪可怕一把的 << 这个连续两个小于的符号了~ 他代表的是『结束的输入字符』的意思!举例来讲:『我要用 cat 直接将输入的讯息输出到 catfile 中, 且当输入 eof 时,该次输入就结束』,那我可以这样做:

[root@linux ~]# cat > catfile <<eof

> This is a test testing

> OK now stop

> eof <==输入这个玩意儿,嘿!立刻就结束了!



看到了吗?利用 << 右侧的控制字符,我们可以终止一次输入, 而不必输入 [crtl]+d 来结束哩!这对程序写作很有帮助喔!好了,那么为何要使用命令输出重导向呢? 这个问题一定会困扰你一下下的,如果你从来都没有写过 script 的话!好了,我们来说一说吧!

  • 当屏幕输出的信息很重要,而且我们需要将他存下来的时候
  • 背景执行中的程序,不希望他干扰屏幕正常的输出结果时;
  • 一些系统的例行命令(例如写在 /etc/crontab 中的档案)的执行结果,希望他可以存下来时;
  • 一些执行命令,我们已经知道他可能的错误讯息,所以想以『 2> /dev/null 』将他丢掉时;
  • 错误讯息与正确讯息需要分别输出时。

当然还有很多很多的功能的,最简单的就是网友们常常问到的:『 为何我的 root 都会收到系统 crontab 寄来的错误讯息呢』这个咚咚是常见的错误, 而

如果我们已经知道这个错误讯息是可以忽略的时候,嗯!『 2> errorfile 』这个功能就很重要了吧! 了解了吗??

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

    在某些时候,我们希望可以一次执行多个指令,例如关机时,希望我可以先执行两次 sync ,然后才 shutdown 计算机,那么可以怎么作呢?这样做呀:

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

  在指令与指令中间利用分号 (;) 来隔开,这样一来,分号前的指令执行完后, 就会立刻接着执行后面的指令了。这真是方便啊~再来,换个角度来想, 万一我想要在某个目录底下建立一个档案,也就是说,如果该目录存在的话, 那我才建立这个档案,如果不存在,那就算了~目录是否存在可以使用一些 bash 提供的判断式功能, 但这里假设我不晓得那个指令,但我知道我可以使用 ls 来判断是否有该目录的存在, 也就是说,我可以利用 ls directoryname
判断是否存在,然后以 touch 建立一个档案, 这两个指令有相关性,那该如何写呢?呵呵!可以利用 && 来作喔!

  [root@linux ~]# ls /tmp && touch /tmp/testingagin

  是否记得我们在变量的章节里面谈过这个奇怪的变数『 $? 』呢? 如果指令执行结果没有错误讯息,那就会回传 $?=0 ,如果有错误, 那回传值就不会是 0 啊!经由这样的判断,我们也可以利用 && 来决定, 当前面的指令执行结果为正确 (例如:仅有 standard output 时),就可以接着执行后续的指令, 否则就予以略过!因此,当 ls /tmp 没有问题,那么就会接着执行 touch /tmp/testingagin 了!
万一是这样:

  [root@linux ~]# ls /vbird && touch /vbird/test

  因为我的系统里面根本就不可能存在 /vbird 这个目录呢!所以,执行 ls /vbird 就会回传错误, 那么后续的 touch /vbird/test 自然就不会动作啰!了解吗? 再换个角度来想,如果我想要当某个档案不存在时,就去建立那个档案, 否则就略过呢?很简单啊~可以这样做:

  [root@linux ~]# ls /tmp/vbirding || touch /tmp/vbirding

  那个 || 刚好完全跟 && 相反,当前一个指令有错误时,在 || 后面的指令才会被执行! (要注意,那个 | 是两个 | ,而 | 按键则是反斜线 \ 同一个按键, 因此,按下 [Shift] 加上 [\] 就会出现那个 | 啰!) 因此,简单的来说,当 ls /tmp/vbirding 发生错误时,才会使用
touch /tmp/vbirding 去建立这个档案的意思。 是否很有趣啊?这个 || 及 && 对于系统管理员在管理某些档案权限、存在等问题时, 可是很有用的东西喔!好了,现在我们来玩比较难一点的,看看底下的例题:

  例题:以 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"

  对不对啊?这其实是有问题的,为什么呢?因为指令是一个一个往下执行,因此,在上面的例子当中,如果 /tmp/vbirding 不存在时,他会:

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

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

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

  所以啊,嘿嘿!第二个例子里面竟然会同时出现 not exist 与 exist 呢!真神奇~经过这个范例的练习,您应该会了解,由于指令是一个接着一个去执行的,因

此,如果真要使用判断, 那么这个 && 与 || 的顺序就不能搞错~一般来说,

  判断式最多会有三个,也就是:

  command1 && command2 || command3

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

放置啰~这很有用的啦!

鸟哥的私房菜:Bash shell(五)-数据流重导向的更多相关文章

  1. 鸟哥Linux私房菜基础学习篇学习笔记3

    鸟哥Linux私房菜基础学习篇学习笔记3 第十二章 正则表达式与文件格式化处理: 正则表达式(Regular Expression) 是通过一些特殊字符的排列,用以查找.删除.替换一行或多行文字字符: ...

  2. 鸟哥Linux私房菜基础学习篇学习笔记2

    鸟哥Linux私房菜基础学习篇学习笔记2 第九章 文件与文件系统的压缩打包: Linux下的扩展名没有什么特殊的意义,仅为了方便记忆. 压缩文件的扩展名一般为: *.tar, *.tar.gz, *. ...

  3. 鸟哥Linux私房菜基础学习篇学习笔记1

    鸟哥Linux私房菜基础学习篇学习笔记1 第三章 主导分区(MBR),当系统在开机的时候会主动去读取这个区块的内容,必须对硬盘进行分区,这样硬盘才能被有效地使用. 所谓的分区只是针对64Bytes的分 ...

  4. [Linux]《鸟哥的私房菜》笔记 (缓慢更新)

    暂时不更新了..这几天一看起书来发现内容很多,这样写blog太慢,也没意义.所以现在是每天看书,在笔记本上记笔记,再配合着<操作系统>和 linux内核 加深理解.往后会以心得体会为主写一 ...

  5. linux: 鸟哥的私房菜

    鸟哥的私房菜 http://vbird.dic.ksu.edu.tw/linux_basic/0320bash.php

  6. 鸟哥Linux私房菜知识汇总8至9章

    一看最近<鸟哥Linux私房菜>. 这是一个基本的书,万丈高楼平地起,学. 这是我整理的一些知识点.尽管非常基础. 希望和大家共同交流. 第8章 Linux磁盘与文件系统管理 一.Linu ...

  7. 鸟哥linux私房菜第6章笔记

    鸟哥linux私房菜第6章笔记 文件权限 修改 chgrp [-R] groupname filename //修改文件所属组 chown [-R] ownername[:groupname] fil ...

  8. 学习鸟哥linux私房菜--安装centos5.6(u盘安装,中文乱码)

    题头为"学习鸟哥Linux私房菜"的内容,均为博主在看鸟哥的Linux私房菜第三版的学习经历收获.以下正文: 鸟哥第一部分讲Linux规则与安装,看到第四章正式开始讲实际安装,于是 ...

  9. 鸟哥的私房菜:Bash shell(六)-管道命令

    就如同前面所说的, bash 命令执行的时候有输出的数据会出现! 那么如果这群数据必需要经过几道手续之后才能得到我们所想要的格式,应该如何来设定? 这就牵涉到管线命令的问题了 (pipe) ,管线命令 ...

随机推荐

  1. console.dir() 与 console.dirxml() 的使用

    在调试JavaScript程序时,有时需要dump某些对象的详细信息.通过手工编写JavaScript代码可以完成这一工作:针对对象的属性进行循环,将循环到的每一个属性值打印出来:可见,这一过程是比较 ...

  2. mariadb/mysql使用Navicat连接报错

    [问题1] 使用Navicat连接服务器的mariadb/mysql时报错 access denied for user root@192.168.xx.xx(using password:yes) ...

  3. Java线程的阻塞

    线程的阻塞 线程的优先级 线程总是存在优先级,优先级范围在1~10之间,线程默认优先级是5(数值越大优先级越高): JVM线程调度程序是基于优先级的抢先调度机制: 在大多数情况下,当前运行的线程优先级 ...

  4. java基础74 XML解析中的SAX解析相关知识点(网页知识)

    1.SAX解析工具 SAX解析工具:是Sun公司提供的,内置JDK中.org.xml.sax.*         点击查看: DOM解析相关知识:以及DOM和SAX解析的原理(区别) 2.SAX解析的 ...

  5. 程序设计分层思想和DAO设计模式的开发

    无论是一个应用程序项目还是一个Web项目,我们都可以按照分层思想进行程序设计.对于分层,当下最流行划分方式是:表现层+控制层+业务层+数据层.其中,业务层和数据层被统称为后台业务层,而表现层和控制层属 ...

  6. 洛谷P1725 琪露诺

    传送门啦 本人第一个单调队列优化 $ dp $,不鼓励鼓励? 琪露诺这个题,$ dp $ 还是挺好想的对不,但是暴力 $ dp $ 的话会 $ TLE $ ,所以我们考虑用单调队列优化. 原题中说她只 ...

  7. java 判断字符串是否相等

    判断字符串相等我们经常习惯性的写上if(str1==str2),这种写法在Java中可能会带来问题. java中判断字符串是否相等有两种方法: 1.用“==”运算符,该运算符表示指向字符串的引用是否相 ...

  8. 有关c语言编程

    有关C语言编程 统计代码"行数" 对于统计代码"行数",行数不包括空白行和注释行.程序改进如下: while(fgets (mystring , 100 , f ...

  9. ubuntu14.04 使用传统的netcat

    Ubuntu上默认安装的是netcat-openbsd,而不是经典的netcat-traditional. 网上例子很多都是以netcat-traditional为例. sudo apt-get -y ...

  10. .net程序员写业务代码需要注意的地方

    代码规范要求1.命名空间规范:dao层的impl实现和接口采用一样的命名空间,到对应文件夹层:IxxDaoContext与其实现类采用顶级命名空间. 2.TableEntity文件夹:所有的实体放到各 ...