异步执行 exec("/alidata/server/php/bin/php /nas/wxdoctor/index.php  App/Common/WordsPic/user_id/".$user_info['user_id']."/goods_id/".$goods_id."."/open_id/".$user_info['open_id']." > /dev/null 2>&1 &");
探讨shell命令中>/dev/null 2>&1的实现原理
 
首先标准输入,标准输出,标准错误:
标准输入是程序可以读取其输入的位置。缺省情况下,进程从键盘读取 stdin 。
标准输出是程序写入其输出的位置。缺省情况下,进程将 stdout 写到终端屏幕上。
标准错误是程序写入其错误消息的位置。缺省情况下,进程将 stderr 写到终端屏幕上。
 
为什么有这三个很重要的概念呢?我们知道,一个程序要运行,需要有输入、输出,如果出错,还要能表现出自身的错误。这是就要从某个地方读入数据、将数据输
出到某个地方,出错了还要把错误给弄到一个地方去.这就够成了数据流(stream)。所以通常情况,每个 Unix
程序在启动时都会打开三个流,一个用于输入,一个用于输出,一个用于打印诊断或错误消息。
有了这三个概念.
 
再说说重定向:
 
数据流重导向(重定向)就是将某个指令(命令)执行后的执行返回值,一般这些返回值就是你执行完后出现在屏幕上那些结果数据,如果我不想让他默认流向屏
幕.那么我可以把这些结果数据传输到其他的地方,例如文件或者装置(例如打印机,不过在Linux里面一切都一切都是文件,所以打印机这样的设备也是文件
咯).这样数据就跑被我导向其他地方了.你懂的.所以东西都输出到屏幕,如果数据太多太乱.我们也受不了啊.而且屏幕的terminal一关.东西就再也
找不到了.如果我重定向到一个文件.这样就可以长期保存执行的日志了.
 
>数据流重导向:输出导向,会替换被导向的文件内容.
>>数据流重导向:输出导向,不会替换被导向的文件内容.会在屁股后面累加数据.
继续看看文件描述符:
维基百科,自由的百科全书上面是这样说的,文件描述符(File
descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。文件描述符在形式上是一个非负整数。实际上,它是一个索引
值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,
一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统

文件描述符的优点主要有两个:基于文件描述符的I/O操作兼容POSIX标准。在UNIX、Linux的系统调用中,大量的系统调用都是依赖于文件描述符。看来这东西还真的有点抽象.也就是说如果程序不打开,文件孤单的在磁盘上面的时候是没有文件描述符的.可以想象一下.第一个打开的文件是0,第二个是1,依此类推。Unix
操作系统通常给每个进程能打开的文件数量强加一个限制。更甚的是,unix
通常有一个系统级的限制。当然真是的情况是0,1,2一般已经被某些概念占用.再加上系统启动后已经不知道打开了多少文件.

所以.我们自己一般打开文件的时候描述符估计也已经到很大的数据了.但是这文件描述符缺点也是有的.比如完成的代码可读性也就会变得很差.你想
啊.0,1,2....22231是知道是啥玩意儿?还好POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和
STDERR_FILENO 来代替 0、1、2。这三个符号常量的定义位于头文件 unistd.h。文件描述符的有效范围是 0 到
OPEN_MAX。一般来说,每个进程最多可以打开 64 个文件(0 — 63)。对于 FreeBSD 5.2.1、Mac OS X
10.3 和 Solaris 9 来说,每个进程最多可以打开文件的多少取决于系统内存的大小,int
的大小,以及系统管理员设定的限制。Linux 2.4.22 强制规定最多不能超过 1,048,576 。

 
综合上面的基本概念:下面的也就不难理解了.
 
标准输入 (stdin) :文件描述符为 0 ,使用 < 或 <<
;(你不会非要写成0<或0<<吧.其实这个也没错.不过太累人了)其实可以理解为这个箭头指向哪里数据就往哪里跑.这里是输入
(stdin).命令就通过<来获取数据.等于数据是从左边往命令里面流.
 
标准输出 (stdout):文件描述符为 1 ,使用 > 或 >>
;(你不会非要写成1>或1>>吧.其实这个也没错.不过太累人了)输出的时候当如不能用<或者<<,因为命令总是
在前面嘛.这里命令要输出数据.所以数据的来源是命令,数据就会随着箭头指向你给的方向.
 
标准错误输出(stderr):文件描述符为 2 ,使用 2> 或 2>>;
 
再举例说明:
 
首先command >file 2>file
的意思是将命令所产生的标准输出信息,和错误的输出信息送到file中.command >file 2>file
这样的写法,stdout和stderr都直接送到file中,
file会被打开两次,这样stdout和stderr会互相覆盖,这样写相当使用了两个同时去抢占file的管道.定向了2次.
 
那如果使用command >file 2>&1 这条命令就将stdout直接送向file, stderr
继承了第一次重定向(FD1)到管道后,再被送往file,此时,file
只被打开了一次,也只使用了一个管道FD1,它包括了stdout和stderr的内容.还可以这样理解.想是把file用管道接通了标准输出.然后把2
代表的标准错误输出接到1代表的标准信息输出上面.就都通向了file了.
 
 从IO效率上,前一条命令的效率要比后面一条的命令效率要低,所以在编写shell脚本的时候,较多的时候我们会用command
> file 2>&1 这样的写法.
 
在看看一个实例(加深相关的理解,此实例引用网上博客.说是intel的笔试题):
 
问题:下面程序的输出是什么?(intel笔试2011)
1
int main(){
2
  fprintf(stdout,"Hello ");
3
  fprintf(stderr,"World!");
4
  return0;
5
}
然后发现输出是
World!Hello
而不是:
Hello World!
 
这是为什么呢?在默认情况下,stdout是行缓冲的,他的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕。而stderr是无缓冲
的,会直接输出,举例来说就是printf(stdout, "xxxx") 和 printf(stdout,
"xxxx\n"),前者会憋住,直到遇到新行才会一起输出。而printf(stderr,
"xxxxx"),不管有么有\n,都输出.
 
最后:
看看什么叫/dev/null
 
1
UFO@UFO~:cd /dev
2
UFO@UFO
:/dev$ls -l null
3
crw-rw-rw-  1 root root 1, 3 Feb 14
 2012 null
看到了吧?是个字符设备文件(c).而这个东西呢?你可以叫他"黑洞",
Blackhole?NO.不是天文学里面的黑洞.它非常等价于一个只写文件. 所有写入它的内容都会永远丢失.
而尝试从它那儿读取内容则什么也读不到. 然而, /dev/null 对命令行和脚本都非常的有用.
再来看看在glibc库的stdio.h头文件中:
 
1
#define    stdin
   (&__sF[0])
2
#define    stdout
   (&__sF[1])
3
#define    stderr
   (&__sF[2])
比如
1
fprintf(stderr, "UFO\n");//那么将把"UFO"作为标准错误输出
在shell命令中,0,1和2分别对应glibc中的stdin,stdout和stderr,上面我们已经大概了解到了:
 
0 对应stdin     即标准输入
1 对应stdout    即标准输出
2 对应stderr    即标准错误输出
所以>/dev/null表示将程序通过printf或者fprintf打印到handle为1的stdout文件的信息,送到/dev/null
空洞文件,/dev/null节点对应的kernel实现就是直接返回写入的字节数,所以程序认为成功存储到/dev/null了,但是>/dev
/null这个操作不能将fprintf(stderr,
"UFO\n")打印到stderr上的字符串送到>/dev/null下,所以必须使用2>&1命令,表示shell将送到2
stderr中的数据转送到1
stdout中,所以这样stderr中会显示到terminal上的信息也将被转送到/dev/null下了.
 
又看个实例吧:
 
01
luther@gliethttp:~$ cat a.c
02
#include
03
int main(int argc, char *argv[])
04
{
05
    fprintf(stdout,"luther
stdout\n");
06
    fprintf(stderr,"luther
stderr\n");
07
    return 0;
08
}
09
luther@gliethttp:~$ gcc a.c
10
luther@gliethttp:~$ ./a.out
11
luther stdout
 
luther stderr
13
luther@gliethttp:~$ ./a.out >/dev/null
14
luther stderr//可以看到>/dev/null操作并不会将stderr信息送到/dev/null下
写一个test.sh脚本
 
01
luther@gliethttp:~$ chmod +x test.sh
02
luther@gliethttp:~$ cat test.sh
03
exec ./a.out >/dev/null
04
luther@gliethttp:~$ ./test.sh
05
luther stderr    
  //可以看到shell也不会将stderr信息送到/dev/null下
06
luther@gliethttp:~$ cat test.sh
07
exec ./a.out >/dev/null 2>&1
08
luther@gliethttp:~$ ./test.sh
09
luther@gliethttp:~$
//什么也没有输出,stderr信息被2>&1命令成功变为stdout信息,进而送入了/dev/null淹没
10
luther@gliethttp:~$ cat test.sh
11
exec ./a.out >/dev/null 1>&2
12
./test.sh
13
luther stdout
14
luther stderr
15
luther@gliethttp:~$
当然对于tee操作也同样存在如上问题,如果打印到stderr的log将不能被tee操作捕获,所以可以将stderr重定向到stdout来解决这个问题,
继续看看实例:
01
luther@gliethttp:~$ ./a.out
02
luther stdout
03
luther stderr
04
luther@gliethttp:~$ ./a.out|tee luther.txt
05
luther stdout
06
luther stderr
07
luther@gliethttp:~$ cat luther.txt
08
luther stdout
09
luther@gliethttp:~$ ./a.out 2>&1|tee luther.txt
10
luther stderr
11
luther stdout
12
luther@gliethttp:~$ cat luther.txt
13
luther stderr
14
luther stdout
15
luther@gliethttp:~$ ./a.out 1>&2|tee luther.txt
16
luther stderr
17
luther stdout
18
luther@gliethttp:~$ cat luther.txt
19
luther@gliethttp:~$
//啥东西都没有,因为stdout被定向到stderr,所以所有log信息都不能被tee捕获
20
 
对于1>&2因为作为一个命令将被shell解析,所以放在哪里都可以,1>&2将影响到该组命令中所有的log输出,比如:
21
luther@gliethttp:~$ 1>&2 ./a.out|tee luther.txt
luther stderr
23
luther stdout
24
luther@gliethttp:~$ ./a.out 1>2 //只输出stderr
25
luther stderr
26
luther@gliethttp:~$ ./a.out 2>1 //只输出stdout
27
luther stdout
 

【转】shell命令中>/dev/null 2>&1的实现原理的更多相关文章

  1. shell脚本中>/dev/null的含义

    shell脚本中>/dev/null的含义 shell脚本中有段使用sqlplus的部分: sqlplus ${user_id} <<! >/dev/null spool sp ...

  2. shell脚本中 /dev/null 的用途

    /dev/null 是一个特殊的设备文件,它丢弃一切写入其中的数据 可以将它 视为一个黑洞, 它等效于只写文件, 写入其中的所有内容都会消失, 尝试从中读取或输出不会有任何结果,同样,/dev/nul ...

  3. shell中>/dev/null 2>&1

    本文转自http://www.kissyu.org/ 背景 我们经常能在shell脚本中发现>/dev/null 2>&1这样的语句.以前的我并没有去深入地理解这段命令的作用,照搬 ...

  4. linux下详解shell中>/dev/null 2>&1

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

  5. (转)详解shell中>/dev/null 2>&1到底是什么

    转 原文地址:https://blog.csdn.net/zouli415/article/details/80651526 前言 相信大家经常能在shell脚本中发现>/dev/null 2& ...

  6. shell中 >/dev/null 2>&1是什么意思

    原文地址:http://juke.outofmemory.cn/entry/295292 我们经常能在 shell 脚本中发现 >/dev/null 2>&1 这样的语句.以前的我 ...

  7. Linux shell命令中expr

    在Linux shell命令中expr虽然不是很起眼,但是它的作用是非常大的!到目前为止,我个人看来最大的作用就是两个——四则运算和字符串的操作. 先说四则运算,在Shell中四则运算不能简简单单的加 ...

  8. linux中>/dev/null 2>&1和2>&1 > /dev/null

    转载:https://www.cnblogs.com/520playboy/p/6275022.html 背景 我们经常能在shell脚本中发现>/dev/null 2>&1这样的 ...

  9. linux中/dev/null与2>&1讲解

    首先先来看下几种标识的含义: /dev/null 表示空设备文件 0 表示stdin标准输入 1 表示stdout标准输出 2 表示stderr标准错误 先看/dev/null command > ...

随机推荐

  1. Libssh认证绕过CVE-2018-10933漏洞复现

    0x00 漏洞描述 libssh 0.6 及以上的版本,在服务端的代码实现中存在身份认证绕过漏洞.在向服务端认证的流程中,攻击者通过将 SSH2_MSG_USERAUTH_REQUEST 消息替换为  ...

  2. 主动分布式WEB资产扫描

      一. Redis的服务安装 系统环境:centos7x64   ip地址:192.168.1.11 1.设置静态IP地址 [root@localhost backlion]#vi /etc/sys ...

  3. 《Linux内核分析》期末总结及学习心得

    [洪韶武 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ] 一.学习心得 本学 ...

  4. bzoj 4358: permu 莫队

    第一步先莫队分块. 对于每一块l~r,初始右端点设为r+1,然后每个询问先将右端点往右移,然后处理询问在l~r之间的部分,最后用一个栈再把l~r的复原. 具体来说是维护两个数组now1和now2,一个 ...

  5. 图解HTTP(六)HTTP首部

    一.HTTP报文的结构: 二.4种首部字段: 1. 通用首部字段 请求报文和响应报文都会使用的首部. 首部字段名 说明 Cache-Control 控制缓存行为 Connection 逐跳首部.连接的 ...

  6. AES-NI指令集

    对于intel的AES-NI新指令集,需要i5处理器及以上的相关硬件支持.在编译时,可能会出现 /usr/lib/gcc/x86_64-linux-gnu/4.8/include/wmmintrin. ...

  7. sql server查询数据库的大小和各数据表的大小

    查询出来的结果中各字段的详细说明参考MSDN资料:https://msdn.microsoft.com/zh-cn/library/ms188776.aspx 如果只是查询数据库的大小的话,直接使用以 ...

  8. 微信图片上传,遇到一个神奇的jgp

    微信图片上传,获取图片base64遇到一个神奇的   jgp var imgFn = function (event) { event.preventDefault(); var id = '#'+$ ...

  9. Shell记录-Shell脚本基础(五)

    Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信 ...

  10. MySQL报错】ERROR 1558 (HY000): Column count of mysql.user is wrong. Expected 43, found 39.

    之前在centos6.4系统安装的是自带的mysql 5.1版本,后来升级到了5.6版本,执行以下命令报错 在网上查找原因说说因为升级不当导致,执行以下命令即可正常执行命令 mysql_upgrade ...