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

ubuntu server pipeline stop process termination when the first exit

本文关键字:进程 终止 退出 服务器 管道 第一次 Ubuntu      更新时间:2023-10-16

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

./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 或更大,因此保存它并在不是变体后处理它。

更正:我的问题是当外部应用程序崩溃时,它会终止myApp。这意味着 while 块之后的任何代码将永远不会运行。所以问题是:有没有办法即使在外部应用程序关闭后运行myApp?

如何正确执行此任务?我插了任何其他想法来完成这项任务。

显示的代码没有任何问题,您的问题中没有任何证据表明显示的代码有任何问题。没有证据表明您的日志记录应用程序实际上收到了要从该外部应用程序写入的"最后一行"。很可能外部应用程序在崩溃之前无法将它们写入标准输出或错误。

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

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

您无法从外壳中执行此操作。您需要编写一些代码来设置它。你可以从阅读 pty(7) 手册页开始,该手册页解释了要遵循的步骤, 此时你会得到文件描述符,你可以使用,并附加到你的外部应用程序。

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

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

signal(SIGHUP,SIG_IGN);

这样我的应用程序执行到最后。 谢谢你的所有答案,至少我学到了很多关于信号和管道的知识。