当我退出时,后台进程stdout和stderr会发生什么?

时间:2021-10-05 20:59:16

I'm trying to understand what happens with stdout and stderr of background processes when exiting an SSH session. I understand about SIGHUP, child processes and all that, but I'm puzzled about the following:

我试图了解退出SSH会话时stdout和stderr后台进程会发生什么。我了解SIGHUP,子进程等等,但我对以下内容感到困惑:

If I run: (while true; do date; sleep 0.5; done) | tee foo | cat >bar and then kill the cat process then the tee process terminates because it can no longer write into the pipe. You can observe this using ps.

如果我跑:(虽然是真的;做日期;睡0.5;完成)| tee foo | cat> bar然后杀死cat进程然后tee进程终止,因为它不能再写入管道。您可以使用ps观察此情况。

But if I run: (while true; do date; sleep 0.5; done) | tee foo & disown and the log out of my SSH session, I can observe that everything continues running just fine "forever". So somehow the stdout of the tee process must "keep going" even though my pty must be gone.

但如果我跑:(虽然是真的;做日期;睡0.5;完成)| tee foo&disown和我的SSH会话退出,我可以观察到一切都在继续运行“永远”。所以不管怎么说,即使我的pty必须消失,开球过程的标准也必须“继续”。

Can anyone explain what happens in the second example?

谁能解释第二个例子中会发生什么?

(Yes, I know I could explicitly redirect stdout/stderr/stdin of the background process.)

(是的,我知道我可以显式重定向后台进程的stdout / stderr / stdin。)

1 个解决方案

#1


1  

This is the crucial loop where tee sends output to stdout and opened files:

这是tee将输出发送到stdout和打开文件的关键循环:

  while (1)
    {
      bytes_read = read (0, buffer, sizeof buffer);
      if (bytes_read < 0 && errno == EINTR)
        continue;
      if (bytes_read <= 0)
        break;

      /* Write to all NFILES + 1 descriptors.
         Standard output is the first one.  */
      for (i = 0; i <= nfiles; i++)
        if (descriptors[i]
            && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
          {
            error (0, errno, "%s", files[i]);
            descriptors[i] = NULL;
            ok = false;
          }
    }

Pay closer attention on this part:

密切关注这一部分:

        if (descriptors[i]
            && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
          {
            error (0, errno, "%s", files[i]);
            descriptors[i] = NULL;
            ok = false;
          }

It shows that when an error occurs, tee would not close itself but just unset the file descriptor descriptors[i] = NULL and continue to keep reading data until EOF or error on input occurs besides EINTR.

它表明,当发生错误时,tee不会自行关闭,只是取消设置文件描述符描述符[i] = NULL并继续保持读取数据,直到除了EINTR之外发生EOF或输入错误。

The date command or anything that sends output to the pipe connected to tee would not terminated since tee still reads their data. Only that the data doesn't go anywhere besides the file foo. And even if a file argument was not provided, tee would still read their data.

由于tee仍然读取其数据,因此date命令或任何将输出发送到连接到tee的管道的命令都不会终止。只有数据不会出现在文件foo之外的任何地方。即使没有提供文件参数,tee仍然会读取他们的数据。

This is what /proc/**/fd looks like on tee when disconnected from a terminal:

这是/ proc / ** / fd在与终端断开连接时在tee上的样子:

0 -> pipe:[431978]
1 -> /dev/pts/2 (deleted)
2 -> /dev/pts/2 (deleted)

And this one's from the process that connects to its pipe:

而这一个来自连接到它的管道的过程:

0 -> /dev/pts/2 (deleted)
1 -> pipe:[431978]
2 -> /dev/pts/2 (deleted)

You can see that tee's stdout and stderr is already EOL but it's still running.

你可以看到tee的stdout和stderr已经是EOL但它仍在运行。

#1


1  

This is the crucial loop where tee sends output to stdout and opened files:

这是tee将输出发送到stdout和打开文件的关键循环:

  while (1)
    {
      bytes_read = read (0, buffer, sizeof buffer);
      if (bytes_read < 0 && errno == EINTR)
        continue;
      if (bytes_read <= 0)
        break;

      /* Write to all NFILES + 1 descriptors.
         Standard output is the first one.  */
      for (i = 0; i <= nfiles; i++)
        if (descriptors[i]
            && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
          {
            error (0, errno, "%s", files[i]);
            descriptors[i] = NULL;
            ok = false;
          }
    }

Pay closer attention on this part:

密切关注这一部分:

        if (descriptors[i]
            && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
          {
            error (0, errno, "%s", files[i]);
            descriptors[i] = NULL;
            ok = false;
          }

It shows that when an error occurs, tee would not close itself but just unset the file descriptor descriptors[i] = NULL and continue to keep reading data until EOF or error on input occurs besides EINTR.

它表明,当发生错误时,tee不会自行关闭,只是取消设置文件描述符描述符[i] = NULL并继续保持读取数据,直到除了EINTR之外发生EOF或输入错误。

The date command or anything that sends output to the pipe connected to tee would not terminated since tee still reads their data. Only that the data doesn't go anywhere besides the file foo. And even if a file argument was not provided, tee would still read their data.

由于tee仍然读取其数据,因此date命令或任何将输出发送到连接到tee的管道的命令都不会终止。只有数据不会出现在文件foo之外的任何地方。即使没有提供文件参数,tee仍然会读取他们的数据。

This is what /proc/**/fd looks like on tee when disconnected from a terminal:

这是/ proc / ** / fd在与终端断开连接时在tee上的样子:

0 -> pipe:[431978]
1 -> /dev/pts/2 (deleted)
2 -> /dev/pts/2 (deleted)

And this one's from the process that connects to its pipe:

而这一个来自连接到它的管道的过程:

0 -> /dev/pts/2 (deleted)
1 -> pipe:[431978]
2 -> /dev/pts/2 (deleted)

You can see that tee's stdout and stderr is already EOL but it's still running.

你可以看到tee的stdout和stderr已经是EOL但它仍在运行。