it-swarm.cn

如何运行将在终端关闭后继续运行的命令?

有时我想开始一个过程而忘了它。如果我从命令行启动它,像这样:

redshift

我无法关闭终端,否则它将终止该过程。我是否可以以不中断进程即可关闭终端的方式运行命令?

339
Matthew

以下2项之一应该起作用:

$ Nohup redshift &

要么

$ redshift &
$ disown

有关其工作原理的更多信息,请参见以下内容:

342
Steven D

如果您的程序为已在运行,则可以使用Ctrl-Z,先用bg将其拉到背景中,然后再用disown将其拉到背景中,如下所示:

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit
147
Stefan

@ StevenD已经发布了很好的答案,但我认为这可能会进一步澄清它。

该进程在终端终止时被终止的原因是,您启动的进程是终端的子进程。一旦关闭终端,这也会杀死这些子进程。您可以使用pstree查看进程树,例如在运行kate &在Konsole中:

init-+
     ├─konsole─┬─bash─┬─kate───2*[{kate}]
     │         │      └─pstree
     │         └─2*[{konsole}]

要在终止kate时使konsole进程与konsole分离,请在命令中使用Nohup,如下所示:

Nohup kate &

关闭konsole后,pstree如下所示:

init-+
     |-kate---2*[{kate}]

kate将继续存在。 :)

一种替代方法是使用screen/tmux/byobu,这将使Shell保持运行,而与终端无关。

50
gertvdijk

您可以在终端中运行这样的过程

setsid process

这将在新会话中运行程序。如解释的 http://hanoo.org/index.php?article=run-program-in-new-session-linux

31
hanoo

尽管所有建议都可以正常工作,但我发现我的替代方法是使用screen,该程序可在屏幕上设置虚拟终端。

您可以考虑以screen -S session_name开头。屏幕几乎可以安装在所有Linux和Unix派生产品上。打 Ctrl+A 和(小写) C 将开始第二个会话。这样一来,您就可以在初始会话之间来回切换 Ctrl+A 和  或点击 Ctrl+A 和 1。一个终端最多可以有十个会话。我曾经在工作中开始一个会话,回家后,在我的工作机中使用ssh,然后调用screen -d -R session_name。这将使您重新连接到该远程会话。

10
apolinsky

我更喜欢:

(应用程序名称和)

例如:[email protected]:~$ (chromium-browser &)

键入命令时,请确保使用括号!

8
daGo

我有一个脚本可以:

  • 在后台运行任意命令

  • 阻止它们被终端窗口杀死

  • 禁止输出

  • 处理退出状态

我主要将它用于geditevinceinkscape等,它们都有很多烦人的终端输出。如果命令在TIMEOUT之前完成,则返回Nohup的退出状态,而不是零。

#!/bin/bash

TIMEOUT=0.1

#use Nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send Nohup's output to /dev/null, supressing Nohup.out
#run Nohup in the background so this script doesn't block
Nohup "${@}" >/dev/null 2>&1 &
Nohup_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $Nohup_PID
Nohup_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $Nohup_STATUS != 0 ] && echo "Error ${@}"
#return the exit status of Nohup, whatever it was
exit $Nohup_STATUS

例子...

>>> run true && echo success || echo fail
success
>>> run false && echo success || echo fail
Error false
fail
>>> run sleep 1000 && echo success || echo fail
success
>>> run notfound && echo success || echo fail
Error notfound
fail
7
jozxyqk

仅使用Shell的方法即可执行以下操作:关闭stdin并后台执行命令:

command <&- & 

这样,当您退出命令行管理程序时,它就不会退出。重定向标准输出是一件不错的选择。

缺点是事实之后您无法执行此操作。

7
w00t

您可以将进程(PID)设置为在注销并关闭终端会话后不接收HUP信号。使用以下命令:

Nohup -p PID
4
tony

可以说它类似于 由apolinsky提供的答案 ,我在screen上使用了一个变体。香草命令是这样的

screen bash -c 'long_running_command_here; echo; read -p "ALL DONE:"'

会话可以通过以下方式断开 Ctrl ACtrl D 并在简单情况下使用screen -r。我将其包装在名为session的脚本中,该脚本位于我的PATH中,可以方便使用:

#!/bin/bash
#
if screen -ls | awk '$1 ~ /^[1-9][0-9]*\.'"$1"'/' >/dev/null
then
    echo "WARNING: session is already running (reattach with 'screen -r $1')" >&2
else
    exec screen -S "$1" bash -c "[email protected]; echo; echo '--------------------'; read -p 'ALL DONE (Enter to exit):'"
    echo "ERROR: 'screen' is not installed on this system" >&2
fi
exit 1

这仅在您事先知道要断开程序连接时才有效。它不提供已运行程序的断开连接。

3
roaima

与以前发布的其他答案类似,由于 reptyr ,因此可以转移运行中的进程以追溯使用“屏幕”,然后关闭终端。在 post 中描述了这些步骤。采取的步骤是:

  1. 暂停流程
  2. 在后台恢复过程
  3. 取消流程
  4. 启动屏幕会话
  5. 查找过程的PID
  6. 使用reptyr接管流程
2
user308879