如何完全从终端分离进程?

350 linux terminal bash shell ubuntu

我在 Ubuntu 上使用 Tilda(下拉式终端)作为我的“命令中心”——几乎就像其他人使用 GNOME Do、Quicksilver 或 Launchy 的方式一样。

但是,我正在努力解决如何将进程(例如 Firefox)与启动它的终端完全分离 - 即防止这样的(非)子进程

  • 关闭始发终端时终止
  • 通过 STDOUT/STDERR“污染”始发终端

例如,为了在“正确的”终端窗口中启动 Vim,我尝试了一个简单的脚本,如下所示:

exec gnome-terminal -e "vim $@" &> /dev/null &
Run Code Online (Sandbox Code Playgroud)

但是,这仍然会导致污染(而且,传递文件名似乎不起作用)。

小智 402

首先; 一旦您启动了一个进程,您可以通过首先停止它(点击Ctrl- Z)然后输入bg让它在后台恢复来将它作为后台。它现在是一个“工作”,而其stdout/ stderr/stdin仍然连接到你的终端。

您可以通过在其末尾附加一个“&”来立即启动一个后台进程:

firefox &
Run Code Online (Sandbox Code Playgroud)

要在后台静音运行它,请使用以下命令:

firefox </dev/null &>/dev/null &
Run Code Online (Sandbox Code Playgroud)

一些额外的信息:

nohup是一个可以用来运行应用程序的程序,这样它的 stdout/stderr 可以被发送到一个文件,这样关闭父脚本就不会 SIGHUP 子脚本。但是,在开始应用程序之前,您需要有先见之明才能使用它。由于工作方式nohup,您不能仅将其应用于正在运行的 process

disown是一个 bash 内置程序,它从 shell 的作业列表中删除一个 shell 作业。这基本上意味着您不能再使用fg, bg,但更重要的是,当您关闭外壳时,它不会再挂起或发送SIGHUP给那个孩子。不像nohupdisown使用的进程已经启动,中背景。

不能做的是在启动进程后更改其 stdout/stderr/stdin。至少不是来自外壳。如果您启动您的进程并告诉它它的标准输出是您的终端(这是您默认执行的操作),那么该进程被配置为输出到您的终端。您的 shell 与流程的 FD 设置无关,这纯粹是流程本身管理的内容。进程本身可以决定是否关闭它的 stdout/stderr/stdin,但是你不能使用你的 shell 来强制它这样做。

要管理后台进程的输出,您可以从脚本中获得很多选项,“nohup”可能是第一个想到的。但是对于您开始但忘记静音 ( firefox < /dev/null &>/dev/null &) 的交互式流程,您真的无能为力。

我建议你获得 GNU screen。使用 screen 您可以在进程的输出变得麻烦时关闭正在运行的 shell 并打开一个新的 shell ( ^Ac)。


哦,顺便说一句,不要$@在你使用它的地方使用“ ”。

$@表示, $1, $2, $3...,这会将您的命令变成:

gnome-terminal -e "vim $1" "$2" "$3" ...
Run Code Online (Sandbox Code Playgroud)

这可能不是您想要的,因为 -e 只接受一个参数。使用$1表明你的脚本只能处理一个参数。

在您提供的场景中(使用gnome-terminal -e),让多个参数正常工作真的很困难,因为-e它只需要一个参数,即一个 shell 命令字符串。您必须将您的参数编码为一个。最好和最健壮但相当笨拙的方式是这样的:

gnome-terminal -e "vim $(printf "%q " "$@")"
Run Code Online (Sandbox Code Playgroud)

  • 使用 `$*` 代替 `$@` 是否已经解决了单独字符串的问题? (3认同)
  • _你不能做的是在启动进程后更改它的 stdout/stderr/stdin。_ - 不完全正确。为此使用 `reptyr`。 (2认同)

小智 220

nohup cmd &
Run Code Online (Sandbox Code Playgroud)

nohup 完全分离进程(守护进程)

  • `nohup` 只是忽略了 `SIGHUP` 信号。它正常执行该过程。没有守护进程。 (31认同)
  • 虽然简洁有价值,但完整更有价值。尽管 nohup 是一个 GNU coreutil,但这里只使用 bash 的答案(或注意没有答案)将是合适的。还是不错的答案。 (6认同)
  • 只是为了澄清:所以“nohup cmd &amp;&gt; /dev/null &amp;disown”将是可行的方法(如果您不想在“nohup.out”文件中输出)? (3认同)
  • @nemo 这意味着进程没有分离,但如果 shell 退出,它会分离(和 `init` 的子进程)......对吗? (2认同)

小智 70

如果您正在使用bash,请尝试;见bash(1)disown [jobspec]

您可以尝试的另一种方法是at now. 如果您不是超级用户,您的使用权限at可能会受到限制。

  • 此外,“disown”似乎对“gnome-terminal”没有预期的效果——当终端退出时,“disown”进程仍然被杀死。我很想知道为什么/如何。 (3认同)
  • `at` 将执行委托给其他人,我喜欢它!+1 (2认同)

小智 49

阅读这些答案,我的初步印象是发行nohup <command> &就足够了。在 gnome-terminal 中运行 zsh,我发现这nohup <command> &并没有阻止我的 shell 在退出时杀死子进程。虽然nohup很有用,尤其是对于非交互式 shell,但它仅在子进程没有为SIGHUP信号重置其处理程序时才保证这种行为。

在我的情况下,nohup应该阻止挂断信号到达应用程序,但子应用程序(在本例中为 VMWare Player)正在重置其SIGHUP处理程序。因此,当终端模拟器退出时,它仍然可能会终止您的子进程。据我所知,这只能通过确保从 shell 的作业表中删除该进程来解决。如果nohup被内置的 shell 覆盖(有时是这种情况),这可能就足够了,但是,如果它不是......


disown是一个外壳内置在bashzshksh93

<command> &
disown
Run Code Online (Sandbox Code Playgroud)

或者

<command> &; disown
Run Code Online (Sandbox Code Playgroud)

如果你喜欢单衬。这通常具有从作业表中删除子进程的理想效果。这使您可以退出终端模拟器而根本不会意外地向子进程发出信号。无论SIGHUP处理程序是什么样子,这都不应该杀死您的子进程。

在拒绝之后,该进程仍然是您的终端模拟器的子进程(pstree如果您想观看它的实际操作,请玩一下),但是在终端模拟器退出后,您应该会看到它附加到 init 进程。换句话说,一切都是它应该的样子,而且你大概希望它是这样。

如果你的 shell 不支持disown怎么办?我强烈建议切换到一个,但如果没有那个选项,你有几个选择。

  1. screen并且tmux可以解决这个问题,但它们是重量更重的解决方案,我不喜欢为这样一个简单的任务运行它们。它们更适合您想要维护 tty 的情况,通常是在远程机器上。
  2. 对于许多用户来说,可能需要查看您的 shell 是否支持像 zsh 的setopt nohup. 这可用于指定SIGHUP在 shell 退出时不应发送到作业表中的作业。您可以在退出 shell 之前应用它,也可以将它添加到 shell 配置中,就像~/.zshrc您总是希望它一样。
  3. 找到一种编辑作业表的方法。我找不到在tcshor 中做到这一点的方法csh,这有点令人不安。
  4. 编写一个小 C 程序来 fork off 和exec(). 这是一个非常糟糕的解决方案,但源代码应该只包含几十行。然后,您可以将命令作为命令行参数传递给 C 程序,从而避免在作业表中出现特定于进程的条目。


小智 36

  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

我已经使用 2 号很长时间了,但 3 号也同样有效。此外,disown具有nohup标志-h,可以使用 拒绝所有进程-a,并且可以使用 拒绝所有正在运行的进程-ar

静音是由 完成的$COMMAND &>/dev/null

希望这可以帮助!


Man*_*d3r 14

bash 最简单且唯一正确的答案:

command & disown
Run Code Online (Sandbox Code Playgroud)

您不必从终端分离进程,而是从外壳分离。


Nat*_*man 9

在 tcsh 中(也可能在其他 shell 中),您可以使用括号来分离进程。

比较一下:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox
Run Code Online (Sandbox Code Playgroud)

对此:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>
Run Code Online (Sandbox Code Playgroud)

这将从工作列表中删除 firefox,但它仍然与终端相关联;如果您通过“ssh”登录到此节点,尝试注销仍会挂起 ssh 进程。


小智 9

我认为 screen 可能会解决您的问题


小智 8

通过子shell取消tty shell运行命令的关联,例如

(命令)&

当退出使用终端关闭但进程仍然存在时。

查看 -

(sleep 100) & exit
Run Code Online (Sandbox Code Playgroud)

打开其他终端

ps aux | grep sleep
Run Code Online (Sandbox Code Playgroud)

进程还活着。


dja*_*fan 5

后台和前台工作可能是每个 Unix 系统管理员应该知道的第一件事。

这是使用 bash 完成的方法:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
Run Code Online (Sandbox Code Playgroud)


小智 4

您可以使用 nohup 命令运行您的命令,这会分离您的进程并将输出重定向到给定文件...但我不确定这正是您所需要的..