我读了一个声称正在运行的用户的答案
foo 2>&1 >& output.log &
Run Code Online (Sandbox Code Playgroud)
foo
即使他们注销,也会导致继续运行。据该用户称,这甚至可以通过 SSH 连接工作。
我并不真正相信这一点,因为我的印象是,在与 SSH 断开连接或终止 TTY 的情况下,shell 及其进程会收到 SIGHUP,导致它们终止。这一点,我的假设下,被使用的唯一理由nohup
在这样的情况下,或者tmux
,screen
等。
然后我查看了glibc 的手册:
该信号还用于向与该会话相关联的作业报告终端上控制进程的终止;此终止有效地断开会话中的所有进程与控制终端的连接。
这似乎证实了我的想法。但进一步看,它说:
如果进程是具有控制终端的会话领导者,则向前台作业中的每个进程发送 SIGHUP 信号,并且控制终端与该会话解除关联。
那么,这是否意味着置于后台的作业将不会收到 SIGHUP?
令我更加困惑的是,我运行了一个交互式 Zsh 会话,运行yes >& /dev/null &
并输入了exit
,当 Zsh 警告我有正在运行的作业时,exit
第二次输入后,它告诉我它已经 SIGHUPed 一个作业。在 Bash 中执行完全相同的操作会使工作继续运行……
我正在尝试创建一个可以运行任意命令的函数,与子进程交互(省略细节),然后等待它退出。如果成功,打字run <command>
看起来就像一个裸的<command>
.
如果我不与子进程交互,我会简单地写:
run() {
"$@"
}
Run Code Online (Sandbox Code Playgroud)
但是因为我需要在它运行时与之交互,所以我使用coproc
和 进行了更复杂的设置wait
。
run() {
exec {in}<&0 {out}>&1 {err}>&2
{ coproc "$@" 0<&$in 1>&$out 2>&$err; } 2>/dev/null
exec {in}<&- {out}>&- {err}>&-
# while child running:
# status/signal/exchange data with child process
wait
}
Run Code Online (Sandbox Code Playgroud)
(这是一个简化。虽然coproc
重定向和所有重定向在这里并没有真正做任何不能做的有用的"$@" &
事情,但我在我的实际程序中需要它们。)
该"$@"
命令可以是任何东西。我拥有的功能可以使用run ls
等等run make
,但是当我这样做时它失败了run vim
。我认为它失败了,因为 Vim 检测到它是一个后台进程并且没有终端访问权限,所以它不会弹出一个编辑窗口,而是自己挂起。我想修复它,以便 Vim 正常运行。
如何coproc "$@"
在“前台”中运行而父 shell 成为“后台”?“与孩子交互”部分既不读取也不写入终端,所以我不需要它在前台运行。我很高兴将 tty 的控制权交给协进程。
对于我正在做的事情来说,重要的run() …