
Если yes
команда выводит "y" непрерывно, пока не будет убита, то она никогда не будет выполнена правильно? Если она никогда не будет выполнена, то как она передает свой вывод следующей команде??
решение1
Программа yes
будет писать в канал, одновременно с считывателем. Если канал пуст, считыватель заблокируется в ядре в вызове read()
ожидания большего ввода. Если канал заполнен, запись заблокируется в ядре в вызове ожидания, write()
пока считыватель освободит некоторое место в канале.
Ядро посылает SIGPIPE
сигнал процессу, если он связывается с записью в канал, у которого нет читателя. Когда процесс чтения закрывает конец чтения канала (явно или в результате его завершения), в следующий раз, когда процесс записи попытается записать в канал, он получит сигнал SIGPIPE
.
Чтобы проиллюстрировать этот момент, рассмотрим эту упрощенную версию программы, yes
которая печатает непрерывный поток y
. Эта программа отличается от yes
тем, что она генерирует сообщение при получении сигнала SIGPIPE
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
static void handler(int sig) {
#define msg "received SIGPIPE signal, terminating\n"
write(2, msg, sizeof msg);
exit(1);
#undef msg
}
int main(void) {
// Instruct the kernel to call the handler() function when
// this process receives the SIGPIPE signal. The default behavior
// when this signal is received is for the process to terminate.
signal(SIGPIPE, handler);
for (;;) {
if (write(1, "y\n", 2) < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 2;
}
}
return 0;
}
Я могу скомпилировать и запустить программу и увидеть, что она ведет себя следующим образом yes
:
$ gcc ex.c -o myes
$ ./myes
y
y
y
...
Если я передам вывод другому процессу, то после завершения этого процесса (и закрытия считывающего конца канала) программа myes
получит SIGPIPE
сигнал (о чем свидетельствует соответствующее сообщение).
$ ./myes | head -n5
y
y
y
y
y
received SIGPIPE signal, terminating