之前一直想写一篇文章总结下,标准输入、标准输出、标准错误,以及我们在前台启动一个程序,以及后台启动一个程序,和这三个之间的关系
1.标准输入、标准输出、标准错误首先这三个对应的是三个文件描述符,这三个对应的文件描述符数值是 0,1,2,而这三个文件描述符是共享的,也就是每一个打开的终端都共享这三个文件描述符,看下下面的表格:
当执行shell命令时,会默认打开3个文件,每个文件有对应的文件描述符来方便我们使用:
| 类型 | 文件描述符 | 默认情况 | 对应文件句柄位置 |
|---|---|---|---|
| 标准输入(standard input) | 0 | 从键盘获得输入 | /proc/self/fd/0 |
| 标准输出(standard output) | 1 | 输出到屏幕(即控制台) | /proc/self/fd/1 |
| 错误输出(error output) | 2 | 输出到屏幕(即控制台) | /proc/self/fd/2 |
所以我们平时在执行shell命令中,都默认是从键盘获得输入,并且将结果输出到控制台上。但是我们可以通过更改文件描述符默认的指向,从而实现输入输出的重定向。比如我们将1指向文件,那么标准的输出就会输出到文件中。
比如现有文件a.log
文本内容为:this is a.log
当我们执行命令cat a.log时,系统默认将其输出到标准输出也就是屏幕,通过符号>我们可以将其输出重定向到另一个文本里:
cat a.log > copya.log
此时我们可以看到copya.log里的文本内容为:this is a.log
事实上,上述命令实际是 cat a.log 1> copya.log的缩写,表示把命令cat a.log的标志输出重定向到copya.log
注意1>是紧挨着的 不能分开写
也就是我们平时的 > 重定向符号 相当于 1>
同样,如果想把标准错误重定向到另一个文件里可以如下操作:cat notexist.log 2> err.log
因为notexist.log不存在,直接执行cat notexist.log报错如下:
cat: notexist.log: No such file or directory
我们打开err.log会发现内容和上面一样,表示把命令的cat: notexist.log的标志错误输入到err.log里面了
一些特殊符号的含义:
> 等价于 1>也就是代表命令的标准输出
/dev/null 可以看作黑洞,等价于一个只写文件。所有写入它的内容都会永远丢失,尝试从它那儿读取内容则什么也读不到。
2表示stderr标准错误
&表示等同于的意思,2>&1,表示2的输出重定向等同于1
前台启动,我们可以看到直接在终端上就是打开一个目录,执行相应的可执行文件就可以了,
然后默认对应的标准输出,和错误输出都是对应这个终端控制台。
具体我参考了一篇知乎上的文章:
详解Linux中nohup和&的用法和区别 - 知乎 示例我们用c代码main.c 做示例,代码的作用是循环输出10000次的hello world!,每次输出后sleep 1秒:具体代码如下:
1 #include2 #include 3 int main(void){ 4 for(int i=0;i<10000;i++){ 5 sleep(1); 6 printf("hello worldn"); 7 } 8 }
gcc main.c -o zzz
生成可执行文件 zzz,如下图,开始执行,每隔1s输出一个helloworld,然后当我按下ctrl+c 以后,程序收到信号SIGINT,自然终止:
hczhang@hczhang-OptiPlex-3050:~/testcommono/testnohup$ ./zzz hello world hello world hello world hello world hello world hello world hello world hello world ^C hczhang@hczhang-OptiPlex-3050:~/testcommono/testnohup$&
使用 ./zzz &,效果如下所示:
[1] 21341 hczhang@hczhang-OptiPlex-3050:~/testcommono/testnohup$ hello world hello world hello world hello world ^C hczhang@hczhang-OptiPlex-3050:~/testcommono/testnohup$ hello world hello world hello world hello world hello world hello world hello world hello world
看到我中间有一次使用了,ctrl+c 发出中断信号,但是退不出来,还是会继续执行,输出hello world,总结如下
首先会在终端显示进程号是21341键入Ctrl + C,发出SIGINT信号,程序会继续运行关掉session,程序会收到一个SIGHUP信号,通过ps aux | grep zzz 可以看到,进程21341也关闭了 nohup
1、使用nohup ./zzz ,效果如下:
hczhang@hczhang-OptiPlex-3050:~/testcommono/testnohup$ nohup ./zzz nohup: ignoring input and appending output to 'nohup.out'
1)前台没有出现进程号
2)有一个“忽略输入并把输出追加到"nohup.out"”的提示
3)hello world 的输出也没有出现在前台
2、如果关掉session,程序会不会关闭呢?
1)使用ps aux | grep zzz 查看进程号
2)关掉session,程序会收到一个SIGHUP信号
3)再次使用ps aux | grep zzz,发现进程仍然存在
4)kill掉进程
3、测试一下Ctrl +C
使用nohup启动zzz,如果键入Ctrl+C ,程序收到SIGINT信号后,直接关闭了
&和nohup同时使用nohup (no hangup 不挂起)放在命令的前面; 标准输出和标准错误缺省会被重定向到nohup.out 文件中。
1、使用nohup ./zzz &运行程序,效果如下:
hczhang@hczhang-OptiPlex-3050:~/testcommono/testnohup$ nohup ./zzz & [1] 26514 hczhang@hczhang-OptiPlex-3050:~/testcommono/testnohup$ nohup: ignoring input and appending output to 'nohup.out'
2、键入Ctrl + C,发送SIGINT信号 使用ps aux查看,进程仍然存在
3、关闭session,发送SIGHUP信号 使用ps aux查看,进程依然存在
4、如果想要终止进程的话,只能使用kill了
总结1、使用&后台运行程序:
1)结果会输出到终端
2)使用Ctrl + C发送SIGINT信号,程序免疫
3)关闭session发送SIGHUP信号,程序关闭
2、使用nohup运行程序:
1)结果默认会输出到nohup.out
2)使用Ctrl + C发送SIGINT信号,程序关闭
3)关闭session发送SIGHUP信号,程序免疫
3、平日线上经常使用nohup和&配合来启动程序:
同时免疫SIGINT和SIGHUP信号,同时把标准错误和标准输出都重定位到黑洞文件里!
nohup ./zzz > /dev/null 2>&1 &



