Попробуйте команду 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.
head
позволяет указать количество строк. Обратитесь к странице руководства для получения дополнительной информации.
loop.py
:
#!/usr/bin/python`
i = 0
while True:
print "This is line " + str(i)
i += 1
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
Обратите внимание, что часть ошибки (Traceback ...
) на самом деле является stderr
, что демонстрируется при запуске ./loop.py 2> stderr.log | head
, так что вам не нужно беспокоиться о выводе головы.
Наконец, для поиска:
$ ./loop.py 2> /dev/null | head | grep -n "line 6"
7:This is line 6
Здесь я перенаправил stderr
из loop.py
, хотя мы уверены, что он не помешает тексту, обработанному head
и grep
РЕДАКТИРОВАТЬ
TL; DR: Планировщик ЦП контролирует, насколько интенсивный процесс будет выполняться после завершения вывода head
.
После некоторого тестирования я обнаружил, что мое решение, хотя и сокращает выполнение loop.py
, не настолько надежно , как это можно сделать. С этими модификациями в моем loop.py
конвейерная обработка его вывода к заголовку приводит к:
новый 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
и вывод:
$ ./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
Я скрыл некоторые результаты и оставил только соответствующие части. В сущности, выходной сигнал показывает , что стандартный ввод head
«ы (и я полагаю , все процессы») / выходные потоки помещаются в буфер.
Согласно этому ответу на SO, после того, как получатель (head
) завершает работу, канал прерывается, и * только когда отправитель (loop.py
) пытается выполнить запись в теперь сломанный канал *, будет отправляться сигнал SIGPIPE.
Поэтому, когда head
получил возможность напечатать свой вывод, все это обнаружилось сразу, но только после того, как loop.py
продолжил еще 247 строк. (Это связано с планированием процессов.) Более того, после того, как head
напечатал свой вывод, но до его завершения, планировщик возобновил loop.py
, поэтому еще 250 строк (до 488) были записаны в канал до того, как канал был разорван.
Для лучших результатов мы можем использовать небуферизованный ввод / вывод (в этом случае небуферизованный вывод 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
Конечно, это просто, если ваша программа написана на python, так как вам не нужно вносить изменения в код. Однако, если он находится в C, и у вас есть источник для него, вы можете использовать функцию setvbuf()
в stdio.h
чтобы установить stdout
как unbuffered:
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;
}