当进程在后台运行时,如何隐藏其标准输出?
例如,
测试文件
#!/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:~$
答案1
重定向正在运行的进程的输出是不容易。但如果你从一开始就努力,可能会有其他选择:
some_long_runnning_command | tail -n 1000 & pkill -STOP tail
使用此方法,由于tail
已SIGSTOP
发送给它,因此它不会输出任何内容,直到您使用 (或类似方法)明确将其带到前台fg
,并且直到脚本完成。调整1000
以获得所需的行数。
更好的选择可能是grep
:
some_long_runnning_command | grep . --color=never & pkill -STOP sed
您可以根据需要发出信号SIGCONT
来启动和SIGSTOP
停止grep
输出。
这可能可以与上面链接的 SO 问题中打开文件描述符的重新连接相结合(也许使用脚本这个答案),以便可以通过已经打开的流程来完成此操作。
如果缓冲确实是问题grep
,因为沃尔克·西格尔指出,那么可以考虑使用更复杂的命令集。首先,请注意sort
用途临时文件,因此缓冲对它来说应该不是问题。它将像tail
和的组合一样工作grep
- 等待命令完成,如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/log
完成.1000000
sed
我还没有设法将它与 GDB 方法集成,但它可以作为一个函数运行,类似于John1024的。问题是你没有很好的方法来知道进程是否已经结束,因为 shell 只在整个作业结束时才通知你。所以你必须使用检查函数:
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 <<EOF
To get the output, do:
kill -CONT $PID
To check if the process has finished, do:
check $(jobs -p %%)
EOF
}
您可以将 包装"$@"
在另一个函数中,一旦作业完成,该函数将通知您,使用类似notify-send
或 之类的方法write
。
这是一次很好的练习,但最终最简单的方法是重定向/dev/null
并忘记输出:如何将后台应用程序的输出重定向到/dev/null。
答案2
/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
在后台运行,则文件描述符 3 是 stdout:
#!/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
该命令将在后台运行,并且其标准输出将被处理。
为了使 的定义bkg
永久化,请将定义放在 中~/.bashrc
。