如果一个命令需要在服务器上长时间运行,通常会用到nohup命令。正在运行的命令不会因此而被迫停止。一般情况下,nohup是和&一起使用的,&表示在后台执行命令。如下:nohupexample.sh&通过&在服务器后台运行exmaple.sh,nohup保证即使当前ssh远程连接中断,example.sh仍然可以在远程服务器继续运行而不受影响。最近有两个配对的测序文件需要和参考基因组比对,可以通过bwa来完成。同时由于文件比较大,运行时间长,为了避免网络连接不稳定导致ssh中断,使用nohupnohupbwamemref.faread1.fq.gzread2.fq.gz>read12。sam&合并两个测序文件并生成一个sam文件。写好命令后,按下回车键,就会有“啪”的一声,非常棒的体验。那就不管了,十几个小时后,生成了一个大文件read12.sam。但是用sam文件生成bam文件时提示sam文件有错误!!!【浪费了十几个小时的计算】仔细查看了sam文件,发现程序运行的结果和程序运行过程中的指令输出到同一个文件!1.标准输出和标准错误标准输出(standardoutput)是结果的默认输出处。例如,在bash中,[plain]viewplaincopy$echo'hello'hello处于默认状态,'hello'isoutputtoyourterminal(终端)显示。再比如通过cat命令显示一个文本文件,[plain]viewplaincopy$cathello.txtHello!这是一个测试!但是,如果当前路径下不存在该文本文件,则会输出错误:此类文件或目录”是标准错误(standarderror)。2.重定向输出默认情况下,标准输出和标准错误都会显示在终端中。如果标准输出不是要在终端输出,而是要输出到另一个文件,这个时候就是重定向输出,可以通过“>”符号来实现。echo'hello'>hello.txt会向hello.txt文件输出“hello”,系统会新建一个文件,如果路径中存在该文件,旧文件将被覆盖。也可以使用“>>”符号,它不会覆盖旧文件,但会在旧文件中添加“hello”。那么,这里有一个问题,是不是所有输出到终端的都可以重定向到一个文件中呢?比如如果是标准错误,是否可以通过“>”输入到文件中?[plain]查看plaincopy$catNo_exist.txt>output.txtcat:No_exist.txt:Nosuchfileordirectory结果证明:没有!output.txt还是一个空文件,错误内容并没有出现在文件中,还是显示在终端!所以不能直接通过“>”将标准错误输出到文件中!那么我们应该如何将标准错误输出到文件中呢?3、文件描述符在bash中,通常用三个整数来表示标准输入(0)、标准输出(1)和标准错误(2)。如果想把标准错误输出到一个文件中,可以使用catNo_exist.txt2>tt.txt这时候在tt中就会出现标准错误“cat:No_exist.txt:Nosuchfileordirectory”。txt文件。同理,我们可以将标准错误输出重定向到标准输出,2>&1如[plain]viewplaincopy$catNo_exist.txtcat:No_exist.txt:Nosuchfileordirectory$catNo_exist.txt2>&1cat:No_exist.txt:Nosuchfileordirectory虽然它们在终端上的输出看起来一样,但它们的身份是不同的。第一个是以标准错误的形式输出,而第二个是标准输出。我们可以通过管道符号来验证它们的区别。[普通]查看plaincopy$catNo_exist.txt|sed's/or/and/'cat:No_exist.txt:没有那个文件或目录$catNo_exist.txt2>&1|sed's/or/and/'cat:No_exist.txt:Nosuchfileanddirectory现在可以看到区别了,第一个标准错误不能通过管道符号将“or”替换为“and”,第二个是标准输出,可以用管道符号把里面的“or”换成“and”。同理,标准输出也可以重定向到标准错误"1>2&"那么回过头来看原题,为什么nohup会同时计算结果和操作的描述呢处理输出到同一个sam文件?为简单起见,使用以下代码(example.sh)在nohup中重现错误。[plain]viewplaincopy!/bin/bashecho“这是结果!”sleep1echo"sleepfor1s">&2echo"这也是结果!"sleep2echo"secondsleepfor2s">&2wheretheprocessdescriptionsleepispassed>&2出现在标准错误上,而结果输出在标准输出上。正常情况下运行:[plain]viewplaincopy$./example.sh>outcome.txtsleepfor1ssecondsleepfor2s$catoutcome.txtthisisoutcome!这也是结局!标准错误直接输出到终端,运行结果输出到outcome.txt,没有任何问题。但是在nohup的情况下,这种情况发生了变化。在nohup的描述中提到“如果标准输出在终端,那么输出的内容会被添加到'nohup.out'文件中;如果标准错误输出在终端,那么输出的内容就会被重定向到标准输出”。这意味着除非另有说明,否则标准输出和标准错误将被重定向到同一个地方。如下,[plain]查看plaincopy$nohup./example.shappending输出到nohup.out$catnohup.outthis是outcome!sleepfor1s这也是结果!secondsleepfor2s不仅出现在nohup.txt文件中我认为想要的运行结果,还有我不想要的运行过程!这也解释了为什么我的sam文件中有很多不应该属于该文件的内容。既然知道了原因,解决问题就不难了。我们可以通过重定向输出的方式,将运行结果和运行过程输出到不同的文件中。[plain]viewplaincopy$nohup./example.sh2>stderr.log1>outcome.txt$catstderr.logsleepfor1ssecondsleepfor2s$catoutcome.txt这就是结果!这也是结果!以标准错误的形式输出到stderr.log,将结果以标准输出的形式输出到outcome.txt。所以本文开头提到的命令可以改为:nohupbwamemref.faread1.fq.gzread2.fq.gz1>read12.sam2>read12.log&summary默认情况下nohup,标准错误和standard输出将被重定向到同一个文件;通过文件描述符(0,1,2)控制输出内容;养成良好的输出控制习惯,区别对待标准输出和标准错误。
