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

2024-01-10

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

for thing in foo bar; do
    {
        background_processor $thing
        cleanup_on_exit $thing
    } &
done

这就是我想要的:我运行 start.sh,它以代码 0 退出,两个子 shell 在后台运行。每个子shell运行background_processor,当它退出时,它会运行cleanup_on_exit。即使我退出最初运行 start.sh 的终端(即使这是一个 ssh 连接),这仍然有效。

然后我尝试了这个:

ssh user@host "start.sh"

这有效,除了之后start.sh已经退出, ssh 显然也在等待子 shell 退出。我真的不明白为什么。一次start.sh退出时,子 shell 成为 pid 1 的子级,并且它们甚至没有分配 tty...所以我无法理解它们如何仍然与我的 ssh 连接相关联。

我后来尝试了这个:

ssh -t user@host "start.sh"

现在进程已经分配了一个伪终端。现在,我发现 ssh 确实会退出start.sh退出,但它也会杀死子进程。

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

ssh -t user@host "nohup start.sh"

这确实有效!所以,我有一个解决我的实际问题的方法,但我想在这里掌握 SIGHUP/tty 内容的微妙之处。

总之,我的问题是:

  1. 为什么 ssh (不带 -t)甚至在之后还要等待子进程start.sh退出,即使它们有父 pid 1?
  2. 为什么 ssh (使用 -t )会杀死子进程(显然是使用 SIGHUP ),即使当我从终端运行它们并从该终端注销时不会发生这种情况?

我想我现在可以解释这一点了!我必须了解一些关于会话和流程组是什么的知识,我通过阅读做到了这一点TTY 揭秘 http://www.linusakesson.net/programming/tty/.

  1. 为什么 ssh(不带 -t)即使在 start.sh 退出后仍等待子进程,即使它们的父进程 pid 为 1?

因为没有 tty,ssh 通过管道(然后由子进程继承)连接到 shell 进程的 stdin/stdout/stderr,并且我正在使用的 OpenSSH 版本 (OpenSSH_4.3p2) 会等待这些套接字在关闭之前退出。某些早期版本的 OpenSSH 并非如此。对此有一个很好的解释,有道理,here http://www.snailbook.com/faq/background-jobs.auto.html.

相反,当使用交互式登录(或ssh -t)、ssh 且进程正在使用 TTY,因此无需等待管道。

我可以通过重定向流来恢复我想要的行为。此变体立即返回:ssh user@host "start.sh < /dev/null > /dev/null 2>&1"

  1. 为什么 ssh (使用 -t )会杀死子进程(显然是使用 SIGHUP ),即使当我从终端运行它们并从该终端注销时不会发生这种情况?

因为 bash 以非交互模式启动,这意味着默认情况下禁用作业控制,因此子进程与父 bash 进程(即会话领导者)位于同一进程组中。当父 bash 进程退出时,内核向其进程组(位于前台)发送 SIGHUP,如下所述setpgid(2):

如果会话有控制终端,...[并且]会话领导者退出,则 SIGHUP 信号将被发送到控制终端的前台进程组中的每个进程。

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

我可以通过使用恢复我想要的行为set -m在 bash 中启用作业控制。如果我添加set -m to start.sh,当 ssh 退出时,孩子们不再被杀死。

谜团解开了:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 ssh 在没有 -t 的情况下等待我的子 shell,并用 -t 杀死它们? 的相关文章

  • 通过 SSH 的 Pygame 不注册击键(Raspberry Pi 3)

    所以我得到了 raspi 3 和简单的 8x8 LED 矩阵 在玩了一些之后 我决定用 pygame 的事件制作一个简单的蛇游戏 显示在该矩阵上 我之前没有 pygame 的经验 除了 LED 矩阵之外 没有连接任何屏幕 显示器 所以最初的
  • 保存和恢复陷阱状态?管理多个陷阱处理程序的简单方法?

    有什么好的方法可以覆盖bash陷阱处理程序不会永久破坏可能已设置或尚未设置的现有处理程序 动态管理任意陷阱例程链怎么样 有没有办法保存陷阱处理程序的当前状态 以便以后可以恢复 在 Bash 中保存和恢复陷阱处理程序状态 我将提交以下堆栈实现
  • apt-get install tzdata 非交互式

    当我尝试 apt get install y tzdata 将显示用于选择时区的命令行选项 我试图在脚本中使用它来进行一些设置 如何在没有用户输入的情况下使 apt get 运行 我知道重新配置 tzdata 我可以做 echo Ameri
  • 将密钥对添加到现有 EC2 实例

    我被给予AWS控制台访问正在运行 2 个实例的帐户 但我无法关闭 在生产中 但是 我想获得对这些实例的 SSH 访问权限 是否可以创建一个新的密钥对并将其应用到实例 以便我可以通过 SSH 访问 获取现有的pem当前无法选择创建实例所用的密
  • 如何显示 zsh 函数定义(如 bash“type myfunc”)?

    如何在 zsh 中显示函数的定义 type foo没有给出定义 在bash中 bash function foo echo hello bash foo hello bash type foo foo is a function foo e
  • 在 Fish Shell 中设置导出

    我安装了多个版本的 PHP 对于我的正常开发 我总是使用通过自制程序安装的 PHP 5 5 x 在鱼壳里 which php php version gt usr local bin php gt PHP 5 5 8 cli built J
  • powershell stdin 管道和重定向

    你好 我一直在制作一个小的跨平台脚 本 我可以将其卷曲并通过管道传输到bash和Powershell中 基本思想是服务器向解释器发送一个命令 然后它给出一个命令将所有输出重定向到标准输出 bash 中的一个例子是 some commands
  • shell_exec 的输出被截断为 100 个字符

    当在 shell 中运行以下命令时 curl F file filename http 192 168 0 1 产生以下输出 Accuracy 0 0 1 classification Accuracy 0 0 1 classificati
  • 在bash中,是否有相当于“错误消息”的东西

    在 perl 中 您可以使用错误消息退出die some msg bash 中是否有等效的单个命令 现在 我正在使用命令来实现这一点 echo some msg exit 1 你可以很容易地自己推出 die echo 1 gt 2 exit
  • Bash 解析和 shell 扩展

    我对 bash 解析输入和执行扩展的方式感到困惑 对于输入来说 hello world 作为 bash 中的参数传递给显示其输入内容的脚本 我不太确定 Bash 如何解析它 Example var hello world displaywh
  • 通过特定分隔符删除字符串

    我的文件中有几列 其中第二列有 分隔符 我想删除第二列中的第一个 第三个和第四个字符串 并将第二个字符串留在该列中 但我有正常的分隔符空间 所以我不知道 input 22 16050075 A G 16050075 A G 22 16050
  • 从 bash 从新的 Google Chrome 浏览器会话获取“用户代理”字符串

    我想要得到用户代理 HTTP 请求标头 https developer mozilla org en US docs Web HTTP Headers User Agent来自 bash 的新 Google Chrome 浏览器会话 刚刚打
  • bash 中 :-(冒号破折号)的用法

    bash中这种风格的含义是什么 PUBLIC INTERFACE eth0 目的是什么 If PUBLIC INTERFACE存在且不为null 则返回其值 否则返回 eth0 实际上有一些记录在bash 手册页 http linux di
  • 如何在 Linux 中编写文本模式 GUI? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 当我编写脚本 程序时 我经常想弹出一个简单的文本 gui 来提示输入 我该怎么做 例如 来自 Shel
  • 如何制作一个 bash 脚本来同时创建 40 个程序实例?

    我是新来的bash and Linux 我编写了一个程序 我想创建多个同时实例 现在 我通过打开 10 个新终端 然后运行该程序 10 次 我运行的命令是php home calculatedata php 使用 bash 脚本执行此操作的
  • 如何在bash中使用jq从变量中包含的json中提取值

    我正在编写一个 bash 脚本 其中存储了一个 json 值 现在我想使用 Jq 提取该 json 中的值 使用的代码是 json val code lyz1To6ZTWClDHSiaeXyxg redirect to http examp
  • bash 行长度限制从何而来?

    在运行 Bash 4 4 19 标准安装 的 Solaris 11 上 输入行似乎有 256 个字符的限制 我想了解这个限制从何而来 我浏览了手册页 但没有找到任何解决此问题的内容 仅当未使用 readline 库时才会发生这种情况 在下面
  • 如何在数组中存储包含双引号的命令参数?

    我有一个 Bash 脚本 它生成 存储和修改数组中的值 这些值稍后用作命令的参数 对于 MCVE 我想到了任意命令bash c echo 0 0 echo 1 1 这解释了我的问题 我将用两个参数调用我的命令 option1 without
  • 有没有办法让我简化这些回声? [复制]

    这个问题在这里已经有答案了 我仍在学习如何编写 shell 脚本 并且我面临着一个挑战 让我更容易回显 Name1 Name2 Name15 我不太确定从哪里开始 我已经想法 但如果我搞砸了 我不想看起来很傻 有什么帮助吗 我实际上还没有尝
  • 两种情况或 if 哪个更快? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我必须制作一个 非常 轻的脚本 它将接受用户的选项并调用脚本中的函数来执行一些任务 现在我可以使用 IF 和 CASE 选项 但我想知道两

随机推荐