“считайте” команду, ожидающую дополнительной новой строки, если введенный проникает через канал

Если я просто работаю read это читает одну строку и сразу выходит, когда Enter нажат.

$ read
typing something here
$

Однако, когда я передаю вход через канал, например, от cat, read ведет себя по-другому и продолжает бежать, пока это не встречается со второй новой строкой:

$ cat | read
typing first line
typing second line
$

Кто-либо может объяснить, почему это - этот путь?

PS: Этот вопрос был вдохновлен тем, Как подать стандартный вход и дамп в файл одновременно?

3
задан 2 September 2017 в 12:30

1 ответ

Это не имеет никакого отношения к новой строке.

Если Вы выполняете свое использование команды strace, Вы узнаете что cat будет получать a SIGPIPE в конце, прежде чем быть закрытым:

$ strace cat | read

...
someOutput
...
+++ killed by SIGPIPE +++
  1. Сначала cat команда добирается для выполнения.
  2. Затем Вы вводите что-то впервые и поражаете Введение.
  3. То, что Вы ввели, будет передано по каналу к read.
  4. cat все еще работает и ожидает EOF.
  5. Вы вводите что-то еще и затем поражаете Введение agian.
  6. На этот раз это не может быть передано по каналу к read, потому что существует нет read больше ожидая входа (это было закрыто после первого канала), если Вы не выполняете его как это:

    cat | while read line; do echo $line; done;
    
  7. 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() вызовы, однако при выполнении его несколько раз, Вы будете видеть по крайней мере два вызова и никогда один.

2
ответ дан 1 December 2019 в 16:54

Другие вопросы по тегам:

Похожие вопросы: