ubuntu 服务器管道停止进程在第一次退出时终止

ubuntu server pipeline stop process termination when the first exit

情况是:我有一个外部应用程序,所以我没有源代码,也无法更改它。在 运行ning 期间,应用程序将日志写入标准错误。任务是编写一个程序来检查它的输出并将输出的某些部分分离到其他文件。我的解决方案是像

一样启动应用程序
./externalApp 2>&1 | myApp

myApp 是一个 c++ 应用程序,来源如下:

using namespace std;

int main ()
{
string str;
ofstream A;
A.open("A.log");

ofstream B;
B.open("B.log");

A << "test start" << endl;

int i = 0;

while (getline(cin,str)) 
{
    if(str.find("asdasd") != string::npos)
    {
        A << str << endl;
    }
    else
    {
        B << str << endl;
    }
    ++i;
}

A << "test end: " << i << " lines" << endl;
A.close();
B.close();

return 0;
}

外部应用程序可能会崩溃或被终止。在那一刻,myApp 也被终止了,它不写最后几行,也不关闭文件。该文件可以是 60Gb 或更大,因此保存它并在不是变体之后处理它。

更正:我的问题是当 externalApp 崩溃时它会终止 myApp。这意味着 while 块之后的任何代码都不会 运行。所以问题是:有没有办法 运行 myApp 即使在 externalApp 关闭之后?

我怎样才能正确完成这个任务?我对完成此任务的任何其他想法感兴趣。

显示的代码没有任何问题,而且您的问题中没有任何证据表明显示的代码有任何问题。没有证据表明您的日志记录应用程序实际上收到了 "the last lines" 以从该外部应用程序写入。很可能是外部应用程序在崩溃之前未能将它们写入标准输出或错误。

最可能的解释是您的外部应用程序检查其标准输出或错误是否连接到交互式终端;如果是这样,它的日志消息的每一行后面都会有一个显式的缓冲区刷新。当外部应用程序的标准输出是管道时,不会发生这种刷新,因此日志消息会缓冲起来,并且仅在应用程序的内部输出缓冲区已满时才刷新。这是一种相当普遍的行为。但正因为如此,当外部应用程序崩溃时,它最后记录的行将永远丢失。因为您的记录器从未收到过它们。您的记录器无法对其从未读取的日志行执行任何操作。

在您的情况下,唯一可用的选项是设置伪 tty 设备并将其连接到外部应用程序的标准输出和错误,使其认为已连接到交互式终端,而其输出实际上由你的申请。

您不能从 shell 执行此操作。您需要编写一些代码来设置它。您可以从 reading the pty(7) manual page 开始,它解释了要遵循的过程,此时您将得到可以获取的文件描述符,并附加到您的外部应用程序。

如果您希望您的程序干净地处理外部程序崩溃,您可能需要处理 SIGPIPE。此信号的默认行为是终止进程。

所以问题不在于当管道的第一个元素结束时它终止了第二个元素。真正的问题是,这两个带有管道的应用程序从 bash 脚本启动,当 bash 脚本结束时,它终止了所有子进程。我使用

解决了它
signal(SIGHUP,SIG_IGN);

我的应用程序就是这样执行到最后的。 谢谢大家的回答,至少我学到了很多关于信号和管道的知识。