Если я просто работаю read
это читает одну строку и сразу выходит, когда Enter нажат.
$ read
typing something here
$
Однако, когда я передаю вход через канал, например, от cat
, read
ведет себя по-другому и продолжает бежать, пока это не встречается со второй новой строкой:
$ cat | read
typing first line
typing second line
$
Кто-либо может объяснить, почему это - этот путь?
PS: Этот вопрос был вдохновлен тем, Как подать стандартный вход и дамп в файл одновременно?
Это не имеет никакого отношения к новой строке.
Если Вы выполняете свое использование команды strace
, Вы узнаете что cat
будет получать a SIGPIPE
в конце, прежде чем быть закрытым:
$ strace cat | read
...
someOutput
...
+++ killed by SIGPIPE +++
cat
команда добирается для выполнения.read
.cat
все еще работает и ожидает EOF.На этот раз это не может быть передано по каналу к read
, потому что существует нет read
больше ожидая входа (это было закрыто после первого канала), если Вы не выполняете его как это:
cat | while read line; do echo $line; done;
cat
будет получать a SIGPIPE
и закрывается.Процесс получает SIGPIPE, когда он пытается записать в канал (названный или не) или сокет типа SOCK_STREAM, который не имеет читателя в запасе. [1]
Получение SIGPIPE
происходит после, когда второй канал происходит.
Например, рассмотрите yes
команда, потому что команда как yes
каналы что-то быстро и неоднократно:
yes | read
это сразу закрывается после второго канала, обратите внимание на два write()
вызовы:
close(3) = 0
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = 8192
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=3542, si_uid=1000} ---
+++ killed by SIGPIPE +++
Хотя, потому что yes
команда слишком быстра, Вы могли бы видеть больше, чем два write()
вызовы, однако при выполнении его несколько раз, Вы будете видеть по крайней мере два вызова и никогда один.