2012-04-05 4 views
17

Это конвейеру команды для генерации 10 символов пароля случайным образом:Почему эта труба оканчивается?

cat /dev/urandom | base64 | head -c 10 

Мой вопрос cat /dev/urandom | base64 бесконечный выходной поток, который не остановится сам по себе. Но почему добавление head -c 10 приводит к тому, что вся труба заканчивается? Я предполагаю, что cat, base64 и head представляют собой 3 отдельных процесса, как может head прекратить действие cat?

ответ

11

После base64 выходы 10 байт, head получает достаточное количество входов и выходов. Когда первый пытается вывести больше байтов, он получит SIGPIPE signal и, следовательно, выйдет тоже. По той же причине cat выйдет по очереди.

23

head закрывает входной файл после считывания необходимой суммы. когда труба закрыта с одной стороны, другая сторона получает ошибки записи; это приводит к закрытию base64, что, в свою очередь, приводит к закрытию cat.

+7

Возможно, стоит упомянуть, что единственная причина, по которой 'head' получает какой-либо вход, заключается в том, что' base64' записывает выходные данные после того, как получает определенный объем ввода, т. Е. Когда его буфер заполнен. Если бы он читал до EOF, он читал бы навсегда, и «голова» никогда не попала в какую-либо трещину. Таким образом, подобный конвейер, например 'cat/dev/urandom | сумма | head -c 10' будет вести себя по-другому, так как 'sum' ждет EOF. –

+3

s/получает ошибки в записи/получает SIGPIPE/ –

+1

Комментарий Роба * крайне важно. Если процесс наследует обработчик SIGPIPE или игнорирует SIGPIPE (например, если он запущен под старым модулем подпроцессов интерпретаторов python) и не проверяет ошибки записи, он не будет завершен. Существует огромная разница между ошибкой записи и получением SIGPIPE, а программы, которые игнорируют обе проблемы, подвержены бесконечному запуску. –

4

трубопроводов работает путем подключения выход одного процесса А на вход B. Соединение может быть нарушена, когда

  • закрывает свой выход. B получит EOF.
  • B закрывает входной сигнал. A получит сообщение об ошибке, что выход больше не доступен, когда он пытается записать следующий байт.

Поскольку эти два случая настолько распространены, обработка была перенесена в стандартную библиотеку C.

+0

Спасибо, но что означает «обработка была перенесена в стандартную библиотеку C»? A и B завершаются оболочкой вместо того, чтобы обнаруживать закрытие ввода/вывода и останавливаться? – Dagang

+0

Когда B закрывает свою сторону трубы, A получит сигнал. Код в процедурах ввода/вывода стандартной библиотеки c.lib ('fprintf()', 'open()', 'read()', ...) обрабатывает сигнал, и вызов функции возвращает return errno EPIPE = «Сломанная труба». –

+1

@ Аарон Дигулла, я не согласен. Я не знаю ни одной библиотеки C, которая устанавливает обработчик SIGPIPE, и мои эксперименты не предлагают. Фактически, SIGPIPE поставляется, что приводит к тому, что любая программа, которая не установила обработчик (то есть 99% всех программ), чтобы выйти. –