Умны ли утилиты Linux при запуске команд по конвейеру?

23

Я только что запустил несколько команд в терминале, и я начал задаваться вопросом, берет ли Unix / Linux ярлыки при выполнении команд по конвейеру?

Например, допустим, у меня есть файл с миллионом строк, первые 10 из которых содержат hello world. Если вы запускаете grep "hello world" file | headкоманду, останавливается ли первая команда, как только она находит 10 строк, или она продолжает поиск всего файла в первую очередь?

DisgruntledGoat
источник
2
Вот почему у GNU grep есть -mаргумент.
Пол Томблин
3
Терминал не имеет к этому никакого отношения. Команды по конвейеру управляются оболочкой.
Кит Томпсон
@KeithThompson простите за мое невежество, я не слишком разбираюсь в терминологии, не был уверен, называть это терминалом, оболочкой или командной строкой. Не стесняйтесь предлагать изменения к моему вопросу :)
DisgruntledGoat

Ответы:

30

Вроде. Оболочка понятия не имеет, что будут выполнять команды, которые вы запускаете, она просто соединяет выход одного с входом другого.

Если grepнайдет более 10 строк с надписью «Привет, мир», то headполучит все 10 нужных строк и закроет канал. Это приведет grepк уничтожению с помощью SIGPIPE, поэтому не нужно продолжать сканирование очень большого файла.

psusi
источник
2
Так что я думаю, из-за условий гонки, grep мог уже прочитать 11-й или 12-й шаблон, но, вероятно, не 100-тысячный?
пользователь неизвестен
3
Частично это зависит от длины строк и размера буфера канала, но краткий ответ заключается в том, что grep будет считывать некоторый разумно ограниченный объем дополнительных данных перед уничтожением.
dmckee
1
@userunknown, точно.
Псуси
Круто, я не знал, что случилось. Я думал, что grepбудет продолжать отправлять вывод в пустоту, как/dev/null
Изката
15

Когда программа пытается выполнить запись в канал, и процесс не читает из этого канала, программа записи получает сигнал SIGPIPE . Действие по умолчанию, когда программа получает SIGPIPE, - завершить программу. Программа может игнорировать сигнал SIGPIPE, и в этом случае запись возвращает ошибку ( EPIPE).

В вашем примере, вот график того, что происходит:

  • grepИ headкоманды запуска параллельно.
  • grep читает некоторый ввод, начинает обрабатывать его.
  • В какой-то момент grepвырабатывается первый блок вывода.
  • head читает этот первый кусок и записывает его.
  • Предполагая, что после первых 10 совпадений будет достаточно строк (в противном случае они grepмогут закончиться первыми), в конечном итоге headбудет напечатано требуемое количество строк. В этот момент headвыходит.
  • В зависимости от относительной скорости из grepи headпроцессов, grepмогут накапливаться некоторые данные и не напечатали его еще. В момент headвыхода grepможет быть чтение ввода или выполнение внутренней обработки, и в этом случае он будет продолжать это делать.
  • Скоро grepвыпишу данные, которые он обработал. В этот момент он получит SIGPIPE и умрет.

Вполне вероятно, что grepобработает немного больше данных, чем строго необходимо, но обычно это всего несколько килобайт:

  • headобычно считывает порциями по несколько килобайт (потому что это более эффективно, чем readсистемный вызов для каждого байта - такое поведение называется буферизацией), поэтому остаток от последнего фрагмента после требуемой последней строки отбрасывается.
  • При передаче могут быть некоторые данные, поскольку каналы имеют связанный буфер, управляемый ядром (часто 512 байт). Эти данные будут отброшены.
  • grepвозможно, накоплены некоторые данные, которые готовы стать выходным блоком (снова буферизироваться). Он получит SIGPIPE, когда попытается очистить свой выходной буфер.

В целом, система точно спроектирована так, что утилиты фильтрации, естественно, работают эффективно. Программы, которые должны продолжать работать, когда их выходной канал отключается, должны игнорировать сигнал SIGPIPE.

Жиль "ТАК - перестань быть злым"
источник
3

Sortof, конвейер работает так: сначала он выполняет первую команду, а затем вторую в вашем случае.

То есть, давайте дадим A|Bкоманду. Тогда нет уверенности в том Aили Bначинает первым. Они могут начаться в одно и то же время, если имеется несколько процессоров. Канал может содержать неопределенный, но конечный объем данных.

Если B пытается прочитать из канала, но данные недоступны, Bбудет ждать, пока данные не поступят. Если при Bчтении с диска Bможет возникнуть та же проблема, и нужно дождаться окончания чтения с диска. Более близкая аналогия - чтение с клавиатуры. Там Bнужно будет ждать, пока пользователь наберет. Но во всех этих случаях B запускает операцию «чтения» и должен дождаться ее завершения. Но если Bэто команда, для которой требуется только частичный вывод, Aто после определенного момента, когда Bуровень входного сигнала s достигнут A, SIGPIPE будет уничтожен

Если Aпопытка записи в канал и канал заполнен, Aнеобходимо дождаться освобождения некоторого места в канале. Aможет иметь такую ​​же проблему, если он пишет в терминал. Терминал имеет управление потоком данных и может контролировать скорость передачи данных. В любом случае, Aон запустил операцию записи и будет ждать, пока операция записи не закончится.

Aи Bведут себя как сопроцессы, хотя не все сопроцессы будут взаимодействовать с каналом. Ни один из них не полностью контролирует другого.

harish.venkat
источник
1
Вопрос заключается в следующем: «что бы сделал А, когда В закроет свою сторону трубы?»
энзотиб
2
Не будет ли это «сломанной трубой»?
Паткос Чаба
1
Если программа пытается читать / писать из / в закрытый канал (например, headвыходит), в программе появляется сигнал SIGPIPE, и по умолчанию происходит выход.
Лекенштейн
Как именно это отвечает на вопрос? Кажется , ответ Псуси короче и ближе к делу .
jw013
1

grepне имеет прямого контроля над каналом (он просто получает данные), а канал не имеет прямого контроля grep(он просто отправляет данные) ...

То grep, что делает любая другая программа, полностью зависит от внутренней логики этих программ. Если вы укажете в параметрах grepкомандной строки сделать ранний выход-при-обнаружении , то это произойдет, в противном случае он будет переходить к самому концу файла в поисках шаблона ...

Терминал также совершенно не связан с внутренними действиями grepи shellдействиями трубопровода ... Терминал - это, в основном, стартовая площадка и выходной дисплей ...

Peter.O
источник