当某些后台进程仍在运行时,命令 'exit' 不起作用

Command 'exit' doesn't work when some background process is still piping out

'exit' 命令对我的情况不起作用,我不明白为什么:

ssh user@mysever <<'HEREDOC'
  echo "1. Running PM2 log..."
  pm2 log &
  echo "2. PM2 log is now in background"
  exit
  echo "3. Won't be here"
HEREDOC

echo "4. Out."

我无法终止 ssh 管道,即使使用上面的 'exit' 命令也是如此。

我能看到第一个回声,第二个回声;当然没有第三次回声;并卡住了。我期望我能看到第四个回声的行为。我必须按 Ctrl+C,然后我看到了第 4 个回声。

找到原因,ssh 隧道等待直到 stdout (EOF) 终止,并且没有进程读取 stdin。

ssh user@myserver <<HEREDOC

  #1. terminate stdout by piping to file
  #2. send to background so it won't read stdin
  pm2 log >log.txt 2>&1 &

  #when going with Bash pipe, end pipe by directing to file
  pm2 log | grep error >log.txt 2>&1 &
HEREDOC

简答:您应该重定向 pm2 进程的标准输入、输出和错误:

pm2 log < /dev/null > /dev/null 2>&1 &

这将阻止远程 ssh 服务器保持会话打开直到 pm2 退出。

更长的答案:

ssh user@mysever <<'HEREDOC'
    ...
    pm2 log &

当您 运行 ssh 这种方式时,远程 ssh 服务器将启动远程用户的 shell 副本来处理会话。为了中继来自远程会话的输入和输出,远程 ssh 服务器将分配一个 TTY 或一组管道。然后它将 TTY 或管道设置为 shell 进程的标准输入、输出和错误。

因此,在远程系统上,您有一个 TTY 或一组管道将远程 shell 进程连接到 SSH 服务器进程。 shell 调用的任何命令都将继承 TTY 或管道集作为命令的标准输入等(除非您使用 shell 功能来重定向标准文件句柄)。

您可能认为 ssh 服务器会在远程 shell 进程退出时终止会话。但事实并非如此。 ssh 服务器在 TTY 或连接到会话标准输出的管道上读取文件结束条件时终止会话。

在你的例子中,你在远程系统上调用这个 pm2 命令,它继承了远程会话的标准输出。只要这个程序是 运行ning,远程 ssh 服务器就不会在标准输出管道上得到 EOF,也不会终止会话。

解决方法是重定向 pm2 进程的输入,使其不继承连接到 ssh 服务器的标准句柄:

pm2 log < /dev/null > /dev/null 2>&1 &

如果您想捕获输出,您可以重定向到一个文件而不是 /dev/null。我认为只有标准输出重定向是绝对必要的,但您也应该重定向标准输入和错误,以确保万无一失。