杀死进程取决于其标准输出输出?

Mah*_*dsi 7 unix command-line

假设我正在运行一个进程,它执行了一个非常冗长的过程,将其进度打印到标准输出。有没有办法在之后自动终止进程

  • x 行输出
  • 在输出中找到某个关键字?

我目前已经将命令的输出通过管道x传输到egrep 'search pattern并希望xegrep显示特定行后终止。

我想如果有什么方法可以编写脚本:

run command `y` after `x` lines of output are seen on previous apps piped `sdout`
Run Code Online (Sandbox Code Playgroud)

我可以很容易地把它拉下来,例如:

mylongrunningtool | egrep '(term1|term2)' | runafterxlines --lines=8 --command='killall -9 mylongrunnigtool`
Run Code Online (Sandbox Code Playgroud)

有接班人吗?

Dmi*_*yev 5

我相信grep接受的答案中的示例并不像OP预期的那样工作(即在输出中出现“第6行”后该进程不会被终止)。要在给出特定输出后终止进程,可以使用

mylongrunningtool | stdbuf -o0 egrep '(term1|term2)' >&-
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:

>&-关闭stdout,因此任何写入尝试都会导致错误。

egrep '(term1|term2)'丢弃除包含关键字(在本例中为“term1”或“term2”)的行之外的所有输出。

stdbuf -o0禁用输出缓冲egrep

一旦在 的输出中遇到关键字之一mylongrunningtoolegrep将尝试将其传递给stdout并以写入错误终止。结果,SIGPIPE将被发送到mylongrunningtool将依次杀死它。

免责声明:

由于信号是异步的,因此mylongrunningtool可能有机会执行关键字为 的语句之后的一些代码stdout,并且基本上不可能保证将执行多少代码。在最坏的情况下,如果向mylongrunningtool设备驱动程序查询持续一小时(或永远)的操作,则它将在被杀死之前再运行一小时(或永远)。

而且,SIGPIPE与 不同的是,可以处理SIGKILL。这意味着mylongrunningtool可以忽略该信号并继续其工作。然而,默认处理SIGPIPE是终止。


lad*_*ini 4

尝试以下head命令:

HEAD(1)                          User Commands                         HEAD(1)

NAME
       head - output the first part of files

SYNOPSIS
       head [OPTION]... [FILE]...

DESCRIPTION
       Print  the  first  10 lines of each FILE to standard output.  With more
       than one FILE, precede each with a header giving the file  name.   With
       no FILE, or when FILE is -, read standard input.
Run Code Online (Sandbox Code Playgroud)

head允许您指定行数。请参阅手册页以获取更多信息。

loop.py:

#!/usr/bin/python`

i = 0
while True:
    print "This is line " + str(i)
    i += 1
Run Code Online (Sandbox Code Playgroud)

loop.py应该无限运行,但是如果我将其输出通过管道传输到head,我得到:

$ ./loop.py | head 
This is line 0
This is line 1
This is line 2
This is line 3
This is line 4
This is line 5
This is line 6
This is line 7
This is line 8
This is line 9
Traceback (most recent call last):
  File "./loop.py", line 6, in <module>
    print "This is line " + str(i)
IOError: [Errno 32] Broken pipe
Run Code Online (Sandbox Code Playgroud)

请注意,错误 ( Traceback ...) 部分实际上是stderr,如运行所示./loop.py 2> stderr.log | head,因此您不必担心 grep 的 head 输出。

最后,进行搜索:

$ ./loop.py 2> /dev/null | head | grep -n "line 6" 
7:This is line 6
Run Code Online (Sandbox Code Playgroud)

在这里,我已经重定向stderrloop.py,尽管我们确信它不会干扰 和 处理的head文本grep

编辑

TL;DR:CPU 调度程序控制密集进程在head完成其输出后运行的数量。

经过一些测试后,我发现我的解决方案虽然确实减少了 的执行loop.py,但并不像人们所能做到的那样健壮。通过对 my 进行这些修改loop.py,将其输出通过管道传输到 head 会产生:

新的loop.py

#!/usr/bin/env python

import sys

def doSomethingIntensive():
    # actually do something intensive here
    # that doesn't print to stdout
    pass

i = 0
while True:
    # printing to stderr so output is not piped 
    print >> sys.stderr, (
            "Starting some calculation that " 
            "doesn't print to stdout")
    doSomethingIntensive()
    print >> sys.stderr, "About to print line " + str(i)
    print "This is line " + str(i)
    print >> sys.stderr, "Finished printing line " + str(i)
    i += 1
Run Code Online (Sandbox Code Playgroud)

和输出:

$ ./loop.py | head
Starting some calculation that doesn't print to stdout
About to print line 0
Finished printing line 0
Starting some calculation that doesn't print to stdout
About to print line 1
Finished printing line 1
Starting some calculation that doesn't print to stdout
About to print line 2
Finished printing line 2
...
About to print line 247
Finished printing line 247This is line 0
This is line 1
This is line 2
This is line 3
This is line 4
This is line 5
This is line 6
This is line 7
This is line 8
This is line 9

Starting some calculation that doesn't print to stdout
About to print line 248
Finished printing line 248
... 
About to print line 487
Finished printing line 487
Starting some calculation that doesn't print to stdout
About to print line 488
Traceback (most recent call last):
  File "./loop.py", line 18, in <module>
    print "This is line " + str(i)
IOError: [Errno 32] Broken pipe
Run Code Online (Sandbox Code Playgroud)

我隐藏了一些输出,只留下了相关部分。本质上,输出表明head(我猜是所有进程)标准输入/输出流都被缓冲了。

根据SO 上的这个答案,一旦接收者(head)终止,管道就会损坏,并且*仅当发送者loop.py尝试写入现已损坏的管道时*才会向其发送 SIGPIPE 信号。

因此,当head有机会打印其输出时,所有输出都会立即显示出来,但只有在loop.py继续打印另外 247 行之后才显示出来。(这与进程的调度有关。)此外,在head打印其输出之后但在终止之前,调度程序恢复loop.py,因此在管道损坏之前,另外约 250 行(最多 488 行)被写入管道。

为了获得更好的结果,我们可以使用无缓冲 I/O(在本例中为 的无缓冲输出loop.py)。通过使用选项调用 python 解释器-u,我们得到:

$ python -u loop.py | head
Starting some calculation that doesn't print to stdout
About to print line 0
Finished printing line 0This is line 0

Starting some calculation that doesn't print to stdout
About to print line 1
Finished printing line 1This is line 1

Starting some calculation that doesn't print to stdout
About to print line 2
Finished printing line 2This is line 2

Starting some calculation that doesn't print to stdout
About to print line 3
Finished printing line 3This is line 3

Starting some calculation that doesn't print to stdout
About to print line 4
Finished printing line 4This is line 4

Starting some calculation that doesn't print to stdout
About to print line 5
Finished printing line 5This is line 5

Starting some calculation that doesn't print to stdout
About to print line 6
Finished printing line 6This is line 6

Starting some calculation that doesn't print to stdout
About to print line 7
Finished printing line 7This is line 7

Starting some calculation that doesn't print to stdout
About to print line 8
Finished printing line 8This is line 8

Starting some calculation that doesn't print to stdout
About to print line 9
Finished printing line 9
This is line 9
Starting some calculation that doesn't print to stdout
About to print line 10
Traceback (most recent call last):
  File "loop.py", line 18, in <module>
    print "This is line " + str(i)
IOError: [Errno 32] Broken pipe
Run Code Online (Sandbox Code Playgroud)

当然,如果您的程序是用 python 编写的,那么这很简单,因为您不需要对代码进行修改。setvbuf()但是,如果它是用 C 语言编写的,并且您恰好有它的源代码,则可以使用in 中的函数stdio.h将其设置stdout为无缓冲:

loop.c:

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1

unsigned long factorial(int n)
{
    return (n == 0) ? 1 : n * factorial(n - 1);
}

void doSomethingIntensive(int n)
{
    fprintf(stderr, "%4d: %18ld\n", n, factorial(n));
}

int main()
{
    int i;

    if (!setvbuf(stdout, NULL, _IONBF, 0)) /* the important line */
        fprintf(stderr, "Error setting buffer size.\n");
    for(i=0; TRUE; i++)
    {
        doSomethingIntensive(i);
        printf("This is line %d\n", i);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)