假设我正在运行一个进程,它执行了一个非常冗长的过程,将其进度打印到标准输出。有没有办法在之后自动终止进程
我目前已经将命令的输出通过管道x
传输到egrep 'search pattern
并希望x
在egrep
显示特定行后终止。
我想如果有什么方法可以编写脚本:
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)
有接班人吗?
我相信grep
接受的答案中的示例并不像OP预期的那样工作(即在输出中出现“第6行”后该进程不会被终止)。要在给出特定输出后终止进程,可以使用
mylongrunningtool | stdbuf -o0 egrep '(term1|term2)' >&-
Run Code Online (Sandbox Code Playgroud)
>&-
关闭stdout
,因此任何写入尝试都会导致错误。
egrep '(term1|term2)'
丢弃除包含关键字(在本例中为“term1”或“term2”)的行之外的所有输出。
stdbuf -o0
禁用输出缓冲egrep
一旦在 的输出中遇到关键字之一mylongrunningtool
,egrep
将尝试将其传递给stdout
并以写入错误终止。结果,SIGPIPE
将被发送到mylongrunningtool
将依次杀死它。
由于信号是异步的,因此mylongrunningtool
可能有机会执行关键字为 的语句之后的一些代码stdout
,并且基本上不可能保证将执行多少代码。在最坏的情况下,如果向mylongrunningtool
设备驱动程序查询持续一小时(或永远)的操作,则它将在被杀死之前再运行一小时(或永远)。
而且,SIGPIPE
与 不同的是,可以处理SIGKILL
。这意味着mylongrunningtool
可以忽略该信号并继续其工作。然而,默认处理SIGPIPE
是终止。
尝试以下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)
在这里,我已经重定向stderr
了loop.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)
归档时间: |
|
查看次数: |
2438 次 |
最近记录: |