若是一个命令须要长时间在服务器上运行,那么不少时候会用到nohup命令,这时即使远程登陆ssh中断了与服务器的联系,那么在服务器上运行的命令也不会所以而被迫中止。shell
一般状况下,nohup与&连用,&的意思是将该命令放在后台执行。以下:bash
nohup example.sh &
将exmaple.sh经过&放在服务器后台运行,nohup确保了即使当前ssh远程链接中断,example.sh仍然可以不受影响,继续在远程服务器中运行。服务器
最近有两个配对测序文件,须要比对到参考基因组上,经过bwa能够完成,同时因为该文件比较大,运行时间长,为了不网络链接不稳定形成ssh中断,使用nohup网络
nohup bwa mem ref.fa read1.fq.gz read2.fq.gz > read12.sam &
将两个测序文件合并并生成sam文件。
写好命令,一个回车键按下去,“啪”一声,那就一个爽。而后不用管它,十余个小时以后,果真生成了一个很大的文件read12.sam文件。
可是,当用该sam文件生成bam文件时,提示错误sam文件存在错误!!!【十余个小时的计算白费了】
仔细检查了一下sam文件,发现程序运行的结果和程序运行过程当中的说明输出到了同一个文件中!app
一、标准输出和标准错误
标准输出(standard output)即结果默认的输出地方,好比在bash中,ssh
$ echo 'hello'
hello
在默认状态下,’hello’时输出到你的终端(terminal)上显示。
再如,经过cat命令显示一个文本文件,ide
$ cat hello.txt
Hello!
This is a test!
可是,若是这个文本文件在当前路径下不存在,在会输出错误:this
$ cat No_exist.txt
cat: No_exist.txt: No such file or directory
这时的输出内容“cat: No_exist.txt: No such file or directory”就是标准错误(standard error)。code
二、重导向输出
默认状况下,标准输出和标准错误都会在终端显示。若是要将标准输出不是输出在终端,而是输出到一个其余文件中,这个时候就是重导向输出,能够经过“>“符号来完成。ip
echo 'hello' > hello.txt
将“hello”输出到hello.txt文件中,系统会新建立该文件,若是路径中存在该文件,旧的文件将会被覆盖。
还可使用”>>”符号,这样不会覆盖旧文件,会将”hello”添加到旧文件中。
那么,这儿有一个问题,是否是全部输出到终端的内容均可以重导向输出到一个文件中?好比,若是是标准错误,可否经过”>”输入到文件中?
$ cat No_exist.txt > output.txt
cat: No_exist.txt: No such file or directory
结果证实:不能!output.txt依旧是一个空文件,而错误内容并无出如今该文件中,依旧在终端显示!因此不能直接经过”>”将标准错误输出到文件中!
那么应该怎样才能将标准错误输出到文件中呢?
三、文件描述符
在bash中,一般使用3个整数来表示标准输入(0)、标准输出(1)和标准错误(2)。
若是要把标准错误输出到文件中,可使用
cat No_exist.txt 2> tt.txt
这时在tt.txt文件中就会出现标准错误“cat: No_exist.txt: No such file or directory”。
一样的道理,咱们能够将标准错误重导向输出为标准输出,2>&1
好比
$ cat No_exist.txt
cat: No_exist.txt: No such file or directory
$ cat No_exist.txt 2>&1
cat: No_exist.txt: No such file or directory
虽然它们在终端上输出的内容看起来没有什么区别,可是它们的身份是不同的,第一个是以标准错误的形式输出的,而第二个是标准输出。咱们能够经过管道符号验证一下它们的不一样。
$ cat No_exist.txt | sed 's/or/and/'
cat: No_exist.txt: No such file or directory
$ cat No_exist.txt 2>&1| sed 's/or/and/'
cat: No_exist.txt: No such file and directory
如今能够看出区别了,第一个标准错误没法经过管道符号把“or”替换成“and”,而第二个是标准输出,能够经过管道符号,把其中的“or”替换成“and”.
一样的道理,也能够将标准输出重导向为标准错误“1 >2&“
那么回过头来,看最开始的那个问题,为何nohup同时会运算结果和运算过程的描述输出到同一个sam文件中呢?
为了简便,用下面的代码(example.sh)重现了nohup中的错误。
#!/bin/bash
echo "this is outcome!"
sleep 1
echo "sleep for 1s" >&2
echo "this is outcome, too!"
sleep 2
echo "second sleep for 2s" >&2
其中sleep的过程描述经过 >&2以标准错误的形式出现,而outcome则以标准输出的形式输出。
正常状况下,运行:
$ ./example.sh > outcome.txt
sleep for 1s
second sleep for 2s
$ cat outcome.txt
this is outcome!
this is outcome, too!
标准错误直接输出到了终端中,运行结果输出到了outcome.txt中,没有任何问题。可是在nohup的状况下,这种状况就变了。
在nohup的说明中,提到“若是标准输出是在终端,那么输出的内容将会被添加到‘nohup.out’文件中;若是标准错误的输出是在终端,那么内容将会被重导向到标准输出“。这就意味着,在没有特殊说明的状况下,标准输出和标准错误将会被重导向输出到同一个地方。以下,
$ nohup ./example.sh
appending output to nohup.out
$ cat nohup.out
this is outcome!
sleep for 1s
this is outcome, too!
second sleep for 2s
在nohup.txt文件中不只出现了我想要的运行结果,还出现了我不想要的运行过程!这也就解释了为何在个人sam文件中会出现不少本不该该属于该文件的内容。
既然知道了缘由,那么解决问题就不难了。咱们能够经过重导向输出,把运行结果和运行过程分别输出到不一样的文件中。
$ nohup ./example.sh 2>stderr.log 1>outcome.txt
$ cat stderr.log
sleep for 1s
second sleep for 2s
$ cat outcome.txt
this is outcome!
this is outcome, too!
这样,将过程以标准错误形式输出到stderr.log中,将结果以标准输出形式输出到outcome.txt中。
因此本文最开头提到的命令能够改成:
nohup bwa mem ref.fa read1.fq.gz read2.fq.gz 1> read12.sam 2>read12.log &
总结
nohup在默认条件下,标准错误和标准输出会重导向到同一个文件中;经过文件描述符(0,1,2)来对控制输出内容;养成良好的输出控制习惯,对标准输出和标准错误要区别对待。
===== THE END =====
参考资料: