shell重定向介绍

无论是用什麽语言开发的程序,都会处理外部的输入,然后将运算结果输出到指定的位置。在交互式的程序中,输入来自用户的键盘和鼠标,结果输出到用户的屏幕,甚至到其他播放设备中。而对于某些后台运行的程序,输入可能来自于外部的一些文件,运算的结果通常又需要写到其他的文件中。比如:程序在运行的过程中,会有一些关键性的信息,比如异常堆栈,外部接口调用情况等,这些都会统统写到日志文件里。
shell脚本也一样,但是我们一般在使用shell命令的时候,更多地还是通过键盘输入,然后直接在屏幕上查看命令的执行结果。如果某些情况下,我们需要将shell命令的执行结果存储到具体文件中,那么我们就需要使用shell中输入/输出的重定向功能。

文件描述符

当执行shell命令时,linux系统会默认打开3个文件,每个文件有对应的文件描述符来方便我们使用:

文件描述符 代表的含义 默认情况 对应文件句柄位置
1 标准正确输出(standard output) 输出到屏幕(即控制台) /proc/self/fd/1
2 标准错误输出(error output) 输出到屏幕(即控制台) /proc/self/fd/2
0 标准输入(standard input) 从键盘获得输入 /proc/self/fd/0

所以我们平时在执行shell命令中,都默认是从键盘获得输入,并且将结果输出到控制台上。但是我们可以通过更改文件描述符默认的指向,从而实现输入输出的重定向。比如我们将1指向文件,那么标准的输出就会输出到文件中。

输出重定向

命令格式 代表的含义
command > filename 把标准正确输出重定向到指定文件中
command 1 > filename 同上
command >> filename 把标准正确输出追加到指定文件中
command 1 >> filename 同上
command 2 > filename 把标准错误输出重定向到指定文件中
command 2 >> filename 同上
  1. “>” 或者 “>>” 符号表示对标准输出(包括正确的和错误的输出)进行重定向。
  2. 这两个符号的左边表示文件描述符,如果没有的话表示1,也就是标准正确输出,符号的右边可以是一个文件,也可以是一个输出设备。
  3. 当使用">" 符号时,会判断右边的文件存不存在,如果存在的话就先删除,然后创建一个新的文件,不存在的话则直接创建。当使用">" 符号时,会判断右边的文件存不存在,如果存在的话就先删除,然后创建一个新的文件,不存在的话则直接创建。
  4. 当使用 “>>” 符号进行追加时,则不会删除原来已经存在的文件。当使用 “>>” 符号进行追加时,则不会删除原来已经存在的文件。
默认情况下:是将标准正确/错误输出—打印到控制台(即屏幕上)
[root@myhost ~]# tree /home/test/
/home/test/
└── a.txt0 directories, 1 file[root@myhost ~]# ll /home/test/a.txt  /home/test/b.txt
ll: cannot access /home/test/b.txt: No such file or directory
-rw-r--r-- 1 root root 0 Jan  4 14:55 /home/test/a.txt#在我们执行 ls /home/test/a.txt  /home/test/b.txt  命令后,一共有两种输出,其中
ll: cannot access /home/test/b.txt: No such file or directory是标准错误输出;
-rw-r--r-- 1 root root 0 Jan  4 14:55 /home/test/a.txt 是标准正确输出。
把标准正确输出重定向到指定文件中,标准错误默认情况
[root@myhost ~]# tree /home/test/
/home/test/
└── a.txt0 directories, 1 file
[root@myhost ~]# ll /home/test/a.txt  /home/test/b.txt > /home/test/default.log
ls: cannot access /home/test/b.txt: No such file or directory[root@myhost ~]# cat /home/test/default.log
-rw-r--r-- 1 root root 0 Jan  4 14:55 /home/test/a.txt-------------------------------------------------------------------------------------------------------------
[root@myhost ~]# tree /home/test/
/home/test/
└── a.txt0 directories, 1 file[root@myhost  ~]#  ll /home/test/a.txt  /home/test/b.txt 1> /home/test/1.log
ls: cannot access /home/test/b.txt: No such file or directory[root@myhost  ~]# cat /home/test/1.log
-rw-r--r-- 1 root root 0 Jan  4 14:55 /home/test/a.txt
把标准错误输出重定向到指定文件中,标准正确默认情况
[root@myhost ~]# tree /home/test/
/home/test/
└── a.txt0 directories, 1 file[root@myhost ~]# ll /home/test/a.txt  /home/test/b.txt 2> /home/test/2.log
-rw-r--r-- 1 root root 0 Jan  4 14:55 /home/test/a.txt[root@myhost ~]# cat /home/test/2.log
ls: cannot access /home/test/b.txt: No such file or directory
把标准正确输出重定向到某个指定文件中,标准错误输出重定向到另外一个指定文件中
[root@myhost ~]# tree /home/test/
/home/test/
└── a.txt0 directories, 1 file[root@myhost ~]#  ll /home/test/a.txt  /home/test/b.txt   1>/home/test/record-1.log   2>/home/test/record-2.log[root@myhost ~]# cat /home/test/record-1.log
-rw-r--r-- 1 root root 0 Jan  4 14:55 /home/test/a.txt
[root@myhost ~]# cat /home/test/record-2.log
ls: cannot access /home/test/b.txt: No such file or directory
把标准正确输出 和 标准错误输出 同时重定向到一个指定文件或者指定设备中

输入重定向

命令格式 代表的含义
command < filename 以filename文件作为标准输入
command 0 < filename 同上
command << filename 以filename文件作为标准输入
command 0 << filename 同上
command <<delimiter 从标准输入中读入,直到遇到delimiter分隔符

我们使用"<" 和 “<<” 符号对输入做重定向,如果符号左边没有写值,那么默认就是0。
现在我们以cat命令为例,如果cat后面没有跟文件名的话,那它的作用就是在输将标准输入(比如键盘)之后按下enter键然后将内容回显到标准输出(比如屏幕)上:

[root@myhost ~]# cat123  #这一排是我输入的
123  #这一排是回显的
456  #这一排是我输入的
456  #这一排是回显的
789  #这一排是我输入的
789  #这一排是回显的

我们可以将利用输入重定向,将我们在键盘上敲入的字符写入到文件中。我们需要使用ctrl+c来结束输入:

[root@myhost ~]# cat  >/home/test/record-to.log
123
test
^C
# cat /home/test/record-to.log
123
test

好了,此时我们觉得自己在键盘上敲比较累,还是直接让cat读取一个文件吧。那么我们需要利用输入重定向:

[root@myhost ~]# touch /home/test/record-show.log
[root@myhost ~]# cat >/home/test/record-show.log
123oldcontent
^C
[root@myhost ~]# cat  /home/test/record-show.log
123oldcontent
---------------------------------------------------------------------------------------------------------------------
[root@myhost ~]# touch /home/test/record-new.log
[root@myhost ~]# cat > /home/test/record-new.log <  /home/test/record-show.log
[root@myhost ~]# cat  /home/test/record-new.log
123oldcontent

神奇的事情发生了,/home/test/record-new.log 文件里面的内容被替换成了/home/test/record-show.log 文件里的内容。那麽同理 << 的作用是 将/home/test/record-show.log 的内容追加到/home/test/record-new.log里面。
我们看到,当我们输入完cat > /home/test/record-to.log,然后敲下回车之后,命令并没有结束,此时cat命令像一开始一样,等待你给它输入数据。然后当我们敲入<< end (即cat >/home/test/record-to.log << end)之后,cat命令就结束了。end之前输入的字符都已经被写入到了/home/test/record-to.log 文件中。这就是输入分割符的作用。

高级用法

1. 重定向绑定(>/dev/null 2>&1 和 &>/dev/null 等价)

>/dev/null

这条命令等同于 1>/dev/null,作用是将标准正确输出1重定向到/dev/null中。 /dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。那么执行了>/dev/null之后,标准正确输出的内容就会不再存在,没有任何地方能够找到输出的内容。

2>&1

这条命令用到了重定向绑定,采用&可以将两个输出绑定在一起。这条命令的作用是将标准错误输出和标准正确输出输出同用一个文件描述符,说人话就是标准错误输出和标准正确输出重定向到同一个地方。
linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令,所以>/dev/null 2>&1的作用就是让标准正确输出重定向到/dev/null中(丢弃标准正确输出),然后标准错误输出由于重用了标准正确输出的描述符,所以标准错误输出也会被定向到了/dev/null中,标准错误输出同样也被丢弃了。执行了这条命令之后,该条shell命令将不会输出任何信息到控制台,也不会有任何信息输出到文件中。

2. 比较一下(>/dev/null 2>&1 和 2>&1 >/dev/null)

上面提到了,linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令。那么我们同样从左到右地来分析2>&1 >/dev/null:

  1. “2>&1”,将标准错误输出绑定到标准正确输出上。由于此时的标准正确输出是默认值,也就是重定向到屏幕上,所以此时标准错误输出会重定向到屏幕上。
  2. “>/dev/null”,将标准正确输出1重定向到/dev/null中。

结论:

命令 标准正确输出 标准错误输出
>/dev/null 2>&1 丢弃 丢弃
2>&1 >/dev/null 丢弃 屏幕

3. 比较一下(>/dev/null 2>&1 和 >/dev/null 2>/dev/null)

为什麽一定要用重定向绑定,而不是像>/dev/null 2>/dev/null这样子分开来一遍呢?现在我们尝试将标准正确输出和标准错误输出都定向到/home/test/record-to.log文件中:

[root@myhost ~]# tree /home/test/
/home/test/
└── a.txt0 directories, 1 file[root@myhost ~]# ll /home/test/a.txt  /home/test/b.txt 1>/home/test/record-to.log  2>/home/test/record-to.log[root@iZbp17qpn8m91l80gz044sZ test]# cat /home/test/record-to.log
-rw-r--r-- 1 root root 0 Jan  4 14:55 /home/test/a.txt
ectory  #这一行不正常

我们看到指定文件接收到额内容并不正常,这是为啥呢?这是因为采用这种写法,标准正确输出和标准错误输出会抢占往/home/test/record-to.log文件的管道,所以可能会导致输出内容的时候出现缺失、覆盖等情况。现在是出现了乱码,有时候也有可能出现只有error信息或者只有正常信息的情况。不管怎么说,采用这种写法,最后的情况是无法预估的。
而且,由于/home/test/record-to.log文件被打开了两次,两个文件描述符会抢占往文件中输出内容,从整体IO效率来讲这种写法也不如>/dev/null 2>&1来得高。

4. 与nohup结合使用

我们经常使用nohup command &命令形式来启动一些后台程序,比如一些java服务:

[root@myhost ~]# nohup java -jar xxxx.jar &

为了不让一些执行信息输出到屏幕上(控制台),我们还会加上刚才提到的>/dev/null 2>&1命令来丢弃所有的输出:

[root@myhost ~]# nohup java -jar xxxx.jar >/dev/null 2>&1 &
[root@myhost ~]# nohup java -jar xxxx.jar &>/dev/null  &

详解shell中的几种标准输出重定向方式相关推荐

  1. sh执行文件 参数传递_详解shell中脚本参数传递的两种方式

    方式一:$0,$1,$2.. 采用$0,$1,$2..等方式获取脚本命令行传入的参数,值得注意的是,$0获取到的是脚本路径以及脚本名,后面按顺序获取参数,当参数超过10个时(包括10个),需要使用${ ...

  2. java 代码块_详解java中的四种代码块

    在java中用{}括起来的称为代码块,代码块可分为以下四种: 一.简介 1.普通代码块: 类中方法的方法体 2.构造代码块: 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行. ...

  3. python open 打开是什么类型的文件-详解Python中open()函数指定文件打开方式的用法...

    文件打开方式 当我们用open()函数去打开文件的时候,有好几种打开的模式. 'r'->只读 'w'->只写,文件已存在则清空,不存在则创建. 'a'->追加,写到文件末尾 'b'- ...

  4. linux下详解shell中/dev/null 21

    前言 相信大家经常能在shell脚本中发现>/dev/null 2>&1这样的语句.以前的我并没有去深入地理解这段命令的作用,照搬照用,直到上周我将这段命令不小心写成了2>& ...

  5. LoRa节点开发:5、代码详解LoRaWAN中的几种数据包(发送与接收数据)

    本文来源微信公众号[物联网思考] 本文主要结合LoRaNode SDK v4.4.2和LoRaWAN规范1.0.3来展开. 1.数据包类型 LoRaWAN规范中有不同的数据包,通过MType字段区分, ...

  6. 详解 Java 中的三种代理模式

    代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用 ...

  7. 详解美股中的几种交易单-限价单、市价单、止损单、止损限价单、跟踪止损单

    1.限价单: 1.1.介绍: 是一种以等于或低于指定价格买进特定数量股票的委托单,或一种以等同或高于指定价格(称为限定价格)卖出股票的委托单. 1.2.例子: 假设我们在市场交易价为$2.45时递交了 ...

  8. 【美股】详解美股中的几种交易单-限价单、市价单、止损单、止损限价单、跟踪止损单

    1.限价单: 1.1.介绍: 是一种以等于或低于指定价格买进特定数量股票的委托单,或一种以等同或高于指定价格(称为限定价格)卖出股票的委托单. 1.2.例子: 假设我们在市场交易价为$2.45时递交了 ...

  9. python爬虫程序详解_Python网络爬虫之三种数据解析方式

    指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据解析.因为大多数情况下的需求,我们都会指 ...

最新文章

  1. [转]ISTQB FL初级认证考试资料(中文)
  2. 大数据-09-Intellij idea 开发java程序操作HDFS
  3. Python 输入输出
  4. 【c语言 gcc9.1.0环境下编译报错】error: ‘true’ undeclared (first use in this function)
  5. nodejs mysql 创建连接池
  6. python获取输入框内容长度_python3 tkinter 获取输入字符串长度
  7. java8电脑版安装包下载百度云_everything电脑文件搜索工具
  8. Apache htaccess的简单总结,以及参数的使用
  9. java string做除法_如果用java来实现传统方式的除法,用String来保存结果,想精确多少位都行,那改怎么做?...
  10. Amazon亲儿子MXNet与其他框架有哪些不同?| 赠书
  11. 「拖放」Mac 的底层能力,也是效率神技
  12. Intel 386 and AMD x86-64 Options for GCC
  13. Technorati使用小结
  14. wamp打开php,wamp本地php环境开启GD库教程
  15. 深入理解Java7.pdf
  16. ltoa() 、itoa()函数实现
  17. 计算机开机桌面黑屏怎么办,电脑启动后黑屏怎么解决
  18. Unix编程需要学习的内容(3)《精通Unix下C语言与项目实践》读书笔记(13)
  19. 一步一步学区块链(1)概念了解
  20. 数据分析完之后的数据展现方式有那些?

热门文章

  1. JupyterHub 安装、环境配置、创建多用户和使用经验
  2. 基于物联网的智能家居
  3. 利用python画各类世界、中国、区县地图(转)
  4. LSM6DS3TR-C姿态传感器的使用(二)---HAL库硬件IIC和官方例程
  5. 合伙做生意长久的原则(不管做哪一行都要阅读)
  6. windows上运行python脚本
  7. Python中pyqtgraph模块结构及用法(1)
  8. timeit 模块详解(准确测量小段代码的执行时间)
  9. 【Android】数据存储,文件,数据库
  10. Qt:36---QSettings