仅当进程在后台运行时才隐藏进程的stdout

只有当它在后台运行时,我怎么能隐藏进程的标准输出?

例如,

test.sh

#!/bin/bash for i in $(seq 200); do echo $i done 

现在,我运行脚本。 我停下来 我把它放回去测试它继续运行。 然后我把它放在背景上,但它继续在标准输出中打印,我无法继续工作。 有没有办法只在背景时重定向或隐藏过程输出?

 dione@saturno:~$ ./test.sh 1 2 3 ^Z [1]+ Detenido ./test.sh dione@saturno:~$ fg %1 ./test.sh 4 5 6 ^Z [1]+ Detenido ./test.sh dione@saturno:~$ %1 & [1]+ ./test.sh & dione@saturno:~$ 7 8 9 10 11 12 13 14 15 fg ./test.sh 16 17 ^C dione@saturno:~$ 

重定向正在运行的进程的输出并不容易 。 但如果你从一开始就工作,可能会有其他选择:

 some_long_runnning_command | tail -n 1000 & pkill -STOP tail 

使用这种方法,由于tailSIGSTOP发送给它,它将不会输出任何东西,直到你使用fg (或类似的东西)明确地将它带到前台,直到脚本完成。 调整1000以获得任意数量的行。

一个更好的选择可能是grep

 some_long_runnning_command | grep . --color=never & pkill -STOP sed 

您可以发信号通知SIGCONTSIGSTOP grep以根据需要启动和停止输出。

这可能与上面链接的SO问题中的打开文件描述符的重新附加相结合(可能与本答案中的脚本一起),以便可以使用已经打开的进程完成此操作。


如果缓存确实是grep一个问题,正如Volker Siegel指出的那样 ,那么人们可能会考虑使用更复杂的命令集。 首先,请注意sort使用临时文件 ,因此缓冲应该不是问题。 它将像tailgrep的组合一样 – 等待命令完成,如tail ,并保持整个输出,如grep 。 就像是:

 some_long_runnning_command | awk '{$0=";"$0}1' | sort -k1.1,1.1 --stable | sed 's/^;//' & pkill -STOP sed 

这里的损失是你不能随意启动和停止输出,并且在无用的sort花费了大量的计算,以及添加和删除的工作;


进一步的测试显示Volker确实是正确的:

对于像(称为test.sh )这样的脚本:

 #! /bin/bash for i in $(seq 1000000); do echo $i; echo $i > /tmp/log; done 

和命令:

 ./test.sh | grep . --color=never & pkill -STOP grep 

/tmp/log被固定在12768(具有相似的数字。并且使用命令

 ./test.sh | awk '{$0=";"$0}1' | sort -k1.1,1.1 --stable | sed 's/^;//' & pkill -STOP sed 

脚本运行完成( /tmp/log1000000 )没有窥视sed


我仍然没有设法将它与GDB方法集成,但是因为它可以作为一个函数使用,类似于John1024 。 问题是你无法知道进程是否已经结束,因为shell只会在整个作业结束时通知你。 所以你必须使用检查function:

 function check () { local PROC=${1:-$(jobs -p %%)} kill -0 $PROC 2>/dev/null && echo "The process is still running." || echo "The process is not running." } function bg () { "$@" | awk '{$0=";"$0}1' | sort -k1.1,1.1 --stable | sed 's/^;//' & local PID=$! sleep 0.1s kill -STOP $PID cat < 

您可以将"$@"包装在另一个函数中,该函数将在作业完成后通知您,使用notify-sendwrite类的东西。

这是一个很好的练习,但最终最简单的方法是重定向到/dev/null并忘记输出: 如何将后台应用程序的输出重定向到/ dev / null 。

仅当脚本在后台运行时,此脚本才会将stdout重定向到/dev/null

 #!/bin/sh case "$(ps -o stat= -p $$)" in *+*) : ;; *) exec 1>/dev/null ;; esac for i in $(seq 200); do echo $i done 

这里的关键是当作业是前景时, ps stat字段中有一个+ 。 如果缺少+ ,我们在后台。

如果你想为某些东西而不是其他东西保持stdout,我们可以为自由选择的输出创建一个文件描述符3,并保持stdout对其他输出有效。 下面的脚本实现了这一点。 它将循环输出发送到文件描述符3.如果作业在前台运行,则文件描述3为stdout;如果作业在后台运行,则为/dev/null

 #!/bin/sh case "$(ps -o stat= -p $$)" in *+*) exec 3<&1 ;; *) exec 3>/dev/null ;; esac for i in $(seq 200); do echo $i done >&3 

在背景和静默中运行任何命令的简单方法

创建这个bash函数:

 bkg() { "$@" >/dev/null & } 

然后,无论何时你想要一个嘈杂的命令,比如seq 200 ,在后台输入:

 bkg seq 200 

该命令将在后台运行,其stdout将被处理掉。

要使bkg永久定义,请将定义放在~/.bashrc