重定向
目录/home/case1下只有一个文件test1.log,无test2.log ,我们执行命令cat test1.log test2.log,结果如下图
上图中我们提取三个信息:标准输入(键盘输入)、标准输出(屏幕显示的正确信息)、错误输出(屏幕显示的错误信息)
我们从专业角度介绍下相关概念:
文件描述符(file description,fd)
相信每个人在学Linux时,都看过这样一句话:Linux 下,一切皆文件。
既然在Linux操作系统中,一切都被抽象成了文件,那么对于一个打开的文件,应用程序就通过文件描述符来对应上。当应用程序请求内核打开/新建一个文件时,内核会返回一个文件描述符用于对应这个打开/新建的文件,读写文件也是需要使用这个文件描述符来指定待读写的文件。
在Linux系统中,就分别使用描述符0、1、2来表示,这3个描述符默认的目标文件(设备)分别是/dev/stdin、/dev/stdout、/dev/stderr,它们分别是各个终端字符设备的软链接。
文件描述符 | 类型 | 默认情况 | 对应设备位置 |
---|---|---|---|
0 | 标准输入(standard input) | 键盘输入 | /dev/stdin |
1 | 标准输出(standard output) | 输出到屏幕 | /dev/stdout |
2 | 错误输出(error output) | 输出到屏幕 | /dev/stderr |
我们也可以cd /dev 看到具体的文件描述符
我们再看下文章开头那张图,执行shell命令是从键盘获得输入cat test1.log test2.log,并且将正确结果和错误结果均输出到屏幕。
那么,这里我们就可以通过更改文件描述符的指向,实现输入、输出的重定向,从而控制输出信息在屏幕的回显和写入到指定文件。
具体操作格式如下:
标准输出重定向
> 把标准输出重定向到新文件中
cat test1.log test2.log 1 >info.log #将1(标准输出)指向文件log.txt,那么标准的输出就会输出到log.txt中
>> 把标准输出追加到文件中
cat test1.log test2.log 1 >>info.log #将1(标准输出)指向文件log.txt,那么标准的输出就会追加到log.txt中
注: 1也可省略不写,默认就是标准输出,
cat test1.log test2.log 1 >ok.log = cat test1.log test2.log >ok.log
cat test1.log test2.log 1 >>ok.log = cat test1.log test2.log >>ok.log
实例1:
实例2:
错误输出重定向
> 把错误输出重定向到新文件中
cat test1.log test2.log 2 >err.log #我们将2(错误输出)指向文件err.log,那么错误的输出就会输出到err.log中
>> 把错误输出追加到文件中
cat test1.log test2.log 2 >>err.log #我们将2(错误输出)指向文件err.log,那么错误的输出就会追加到err.log中
实例3:
实例4:
在上述实例1、实例2中,我们将标准输出重定向到了ok.log文件中,所以屏幕(控制台)只剩下了错误提示。
在例3、实例4中我们将错误输出重定向到了err.log文件中,所以屏幕(控制台)只剩下了正确提示。
我们也可以把操作放在一个命令执行,将标准输出重定向到ok.log文件中,同时将错误输出重定向到err.log
实例5:
Tips:>和>>区别
当使用
>
时,会判断右边的文件log.txt是否存在,如果存在就删除掉,再重新创建一个log.txt;如果不存在,则直接创建log.txt。当使用
>>
进行时,会判断右边的文件log.txt是否存在,如果存在也不会删除,而是在log.txt结尾继续追加新的内容,如果不存在,则直接创建log.txt。
有时候我们不喜欢屏幕回显任何信息,也不需要把这些信息写到文件中去,我们就可以用到/dev/null来处理。
何为/dev/null?
/dev/null:表示的是一个黑洞,也就是空设备文件,通常用于丢弃不需要的数据输出, 或者用于输入流的空文件,可想象为回收站,把不要的数据统统扔进去
cat test1.log test2.log 1>/dev/null #把标准输出扔掉,屏幕仅显示错误输出信息,且不会保存到任何文件
cat test1.log test2.log 2>/dev/null #把错误输出扔掉,屏幕仅显示标准输出信息,且不会保存到任何文件
cat test1.log test2.log >/dev/null 2>&1 #把标准输出、错误输出均扔掉,屏幕不显示任何信息,且不会保存到任何文件
上面>/dev/null 2>&1是什么意思呢,也就是1> /dev/null 2>&1,详细解释下:
重定向绑定2>&1
使用&将两个标准输出和错误输出绑定到一起,使其输出到同一个文件描述符
实例6:
执行过程:这条语句是从左到右依次执行的,开始错误输出会输出到标准输出,此时标准输出的内容会包含错误输出,最后/dev/null仅被标准输出打开。
所以执行结果是:屏幕不会回显任何信息,也不会有把任何信息输出到文件中。
注意!!!
为什么 >/dev/null 2>&1不等同于 2>&1 >/dev/null
上文已经说过这条语句执行顺序是从左往右,2>&1写在/dev/null前面,错误输出指向标准输出,还是会回显在屏幕上,而只会把标准输出扔到/dev/null
说到这里,有的人就仍不住抛出疑问了,这么写花里胡哨,还容易出错,何不像下面这样去写简单粗暴:
为什么>/dev/null 2>&1不要写为1>/dev/null 2>/dev/null
实例7:
实例8:
原因:这种写法,其实标准输出和错误输出会抢占输出同一个文件的管道,都打开同一个文件/dev/null,有相互复覆盖的影响,
从实例7、实例8可以看到,随时有覆盖、回显错误输出等情况发生。所以我们只能不用这种写法,嘿嘿。
exec绑定重定向
我们发现,上面讲的输入输出重定向,都是只对当前执行的那条指令有效。那如何使得接下来所有命令有效呢?
我们可以扩展自己新的描述符,对文件进行读写操作。我们可以通过exec命令绑定来处理这种情况。
实例9:
绑定文件描述符
exec
8>&1 #将标准输出与文件描述符8绑定
查看文件描述符
ls
/proc/self/fd/
#可以查看到文件描述符8
将标准输出绑定到文件
exec
1>log #将接下来所有命令的标准输出,都输出到log文件中
实例10:
那如何解绑呢?
实例11:
解绑恢复标准输出
exec
1>&8 #恢复标准输出
关闭文件描述符
exec
8>&- #关闭文件描述符8
&>/dev/null
不管是什么文件描述符,都可以重定向到/dev/null
输入重定向
介绍了输出重定向,输入重定向也很好理解了,你看就符号(<)和输出重定向(>)是反的
< input 以input文件作为标准输入
unzip test1.zip test2.zip 0 <log.txt #将log.txt文件内容作为标准输入
注: 0也可省略不写,默认就是标准输入,
unzip test1.zip test2.zip 0 <log.txt = unzip test1.zip test.zip <log.txt
实例12:
让cat读取input.txt的内容,并写到log文件中。
<< delimiter 从标准输入中读入,直到遇到delimiter分隔符
delimiter分隔符可以是任意字符,如over
unzip test1.zip test2.zip <<over #从标准输入中读入,直到遇到over分隔符,当遇到over分隔符
实例11:
我们看下cat >info的例子,cat 的作用就是将标准输入(键盘)回显到标准输出(屏幕)上,cat >info就是讲内容写入到info文件中。
过程中,我们只能使用ctrl+c才能结束输入。
实例13:
实例14:
我们在实例11的基础上加上<<over
,变为cat >info<<over,通过下面例子演示我们看下这里的分割符(over)的作用
过程中,我们可以不使用ctrl+c结束输入,可以通过键盘输入over结束输入
使用场景
1、nohup结合
2、打印屏幕信息打印留做日志分析
3、防止后台执行程序打印信息干扰工作
4、过滤错误信息
5、将csv格式的数据文件自动转换为sql insert语句
6、等等
(待最近补充)
一张图总结
讲了这么多,文章最后用一张图总结一下:
(待最近补充)
very nice !ery nice !
shell脚本中发现>/dev/null 2>&1
这样的语句,在工作中用到最多的就是nohup command >/dev/null 2>&1 &
命令,希望大家能够好好掌握。
nohup /usr/local/kafka_2.11-2.3.0/bin/kafka-server-start.sh /usr/local/kafka_2.11-2.3.0/config/server.properties 1>/dev/null 2>&1&
tar -zxvf mysql-5.7.31-el7-x86_64.tar.gz >/dev/null 2>&1
yum -y install gcc >/dev/null 2>&1
port=6379
npid=$(netstat -nlp | grep :$port | awk '{print $7}' | awk -F"/" '{ print $1 }');
if [ -z "$npid" ] && [ "$npid" -gt 0 ] 2>/dev/null; then
echo "kill -9 $npid"
kill -9 $npid;