Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 为什么ssh在没有-t的情况下等待我的子shell,然后用-t杀死它们?_Bash_Ssh_Tty_Subshell - Fatal编程技术网

Bash 为什么ssh在没有-t的情况下等待我的子shell,然后用-t杀死它们?

Bash 为什么ssh在没有-t的情况下等待我的子shell,然后用-t杀死它们?,bash,ssh,tty,subshell,Bash,Ssh,Tty,Subshell,我有一个bash脚本start.sh,如下所示: for thing in foo bar; do { background_processor $thing cleanup_on_exit $thing } & done 这就是我想要的:我运行start.sh,它以代码0退出,两个子shell在后台运行。每个子shell运行background\u处理器,当处理器退出时,它会在退出时运行cleanup\u。即使我退出最初运行start.

我有一个bash脚本start.sh,如下所示:

for thing in foo bar; do
    {
        background_processor $thing
        cleanup_on_exit $thing
    } &
done
这就是我想要的:我运行start.sh,它以代码0退出,两个子shell在后台运行。每个子shell运行
background\u处理器
,当处理器退出时,它会在退出时运行
cleanup\u。即使我退出最初运行start.sh的终端(即使这是一个ssh连接),这也可以工作

然后我试了一下:

ssh user@host "start.sh"
ssh -t user@host "start.sh"
这是可行的,除了退出
start.sh
之后,ssh显然也在等待子shell退出。我真的不明白为什么。一旦退出
start.sh
,子shell将成为pid 1的子shell,并且它们甚至没有分配tty。。。因此,我无法理解它们如何仍然与我的ssh连接相关联

我后来试过:

ssh user@host "start.sh"
ssh -t user@host "start.sh"
现在,进程有一个指定的伪tty。现在,我发现只要
start.sh
退出,ssh就会退出,但它也会杀死子进程

我猜在后一种情况下,子进程正在被发送,所以我这样做:

ssh -t user@host "nohup start.sh"
这确实有效!所以,我有一个解决我实际问题的方法,但我想在这里抓住SIGHUP/tty的微妙之处

总之,我的问题是:

  • 为什么ssh(不带-t)即使在
    start.sh
    退出后也要等待子进程,即使它们有父进程pid 1
  • 为什么ssh(带-t)会杀死子进程,显然是通过SIGHUP,即使当我从终端运行它们并从该终端注销时不会发生这种情况
  • 我怀疑(但我假设)当没有tty时,bash会将SIGHUP传递给您的forked进程,该进程自己处理信号,并悄悄地忽略它并继续绑定SSH会话


    但是,由于您和进程之间有一个tty,tty驱动程序正在拦截SIGHUP,意识到它已经失去了用户,并在没有ssh会话作为父会话的情况下自行运行。

    我想我现在可以解释这一点了!我必须通过阅读了解会话和过程组是什么

  • 为什么ssh(不带-t)即使在start.sh退出之后也要等待子进程,即使它们有父进程pid 1
  • 因为没有tty,ssh通过管道(然后由子进程继承)连接到shell进程的stdin/stdout/stderr,而我使用的OpenSSH版本(OpenSSH_4.3p2)在退出之前等待这些套接字关闭。一些早期版本的OpenSSH没有这样做。对此有一个很好的解释,有理由

    相反,当使用交互式登录(或
    ssh-t
    )时,ssh和进程使用TTY,因此没有管道等待

    我可以通过重定向流来恢复所需的行为。此变量立即返回:
    sshuser@host“start.sh/dev/null 2>&1”

  • 为什么ssh(带-t)会杀死子进程,显然是通过SIGHUP,即使当我从终端运行它们并从该终端注销时不会发生这种情况
  • 因为bash是在非交互模式下启动的,这意味着默认情况下禁用作业控制,因此子进程与父bash进程(即会话负责人)位于同一进程组中。当父bash进程退出时,内核向其进程组(位于前台)发送SIGHUP,如
    setpgid(2)
    中所述:

    如果会话有一个控制终端。。。[和]会话引导器退出,SIGHUP信号将发送到控制终端前台进程组中的每个进程

    相反,当使用交互式登录时,bash处于交互式模式,这意味着默认情况下启用作业控制,因此子进程进入一个单独的进程组,并且在我退出时从未收到SIGHUP

    我可以通过使用
    set-m
    在bash中启用作业控制来恢复所需的行为。如果我将
    set-m
    添加到
    start.sh
    ,则ssh退出时不再杀死子级


    谜团已解开:)

    用“nohup”预先准备好任何你不想让这件事发生的电话。

    PS:如果我有时间,我计划阅读和消化,之后也许我能回答上面的问题。。。