Чи розумні утиліти Linux під час виконання трубних команд?


23

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

Наприклад, скажімо, у мене є файл з мільйоном рядків, перші 10 з яких містять hello world. Якщо ви запускаєте команду, grep "hello world" file | headчи зупиняється перша команда, як тільки вона знаходить 10 рядків, чи продовжує спочатку шукати весь файл?


2
Ось чому gnu grep має -mаргумент.
Пол Томблін

3
Термінал не має нічого спільного з цим. Трубопровідними командами управляє оболонка.
Кіт Томпсон

@KeithThompson вибачте за моє незнання, я не терміновий, я не був впевнений, чи називати це терміналом, оболонкою чи командним рядком. Не соромтеся запропонувати зміни на моє запитання :)
НезадоволенеЗапитання

Відповіді:


30

Типу. Оболонка не має уявлення про те, що будуть виконувати команди, які ви виконуєте, вона просто підключає вихід однієї до входу іншої.

Якщо ви grepзнайдете більше 10 рядків, на яких написано "привіт світ", тоді headвсі 10 ліній, які він хоче, закриють трубу. Це призведе grepдо вбивства за допомогою SIGPIPE, тому не потрібно продовжувати сканувати дуже великий файл.


2
Тож я здогадуюсь, через умови перегонів греп, можливо, вже прочитав 11 чи 12 шаблон, але, мабуть, не 100 тис.?
користувач невідомий

3
Частково це залежить від довжини ліній і розміру буфера труби, але коротка відповідь полягає в тому, що grep зчитує деяку досить обмежену кількість зайвих даних перед тим, як вбити.
dmckee

1
@userunknown, точно.
psusi

Класно, я не знав, що це сталося. Я думав , що grepбуде продовжувати посилати вихід в порожнечу, подібно/dev/null
Izkata

15

Коли програма намагається записати в трубку, і з неї не відбувається зчитування процесу, програма запису отримує сигнал SIGPIPE . Дія за замовчуванням, коли програма отримує SIGPIPE, - це припинити програму. Програма може вибрати ігнорувати сигнал SIGPIPE, і в цьому випадку запис повертає помилку ( EPIPE).

У вашому прикладі ось часова шкала того, що відбувається:

  • Команди grepта headкоманди запускаються паралельно.
  • grep читає деякий вхід, починає його обробляти.
  • У якийсь момент grepвиробляє перший фрагмент продукції.
  • head читає цей перший шматок і записує його.
  • Якщо припустити, що після перших 10 матчів буде достатньо рядків (інакше grepможе закінчитися перший), врешті-решт headбуде надруковано потрібну кількість рядків. У цей момент headвиходить.
  • Залежно від відносної швидкості grepта headпроцесів, grepможливо, накопичені деякі дані та ще не надруковані. Під час headвиходу, grepможливо, відбувається читання вводу або внутрішня обробка, і в цьому випадку це буде продовжуватися.
  • Незабаром випишуть grepоброблені дані. У цей момент він отримає ПІДПИС і помре.

Цілком ймовірно, що grepви обробите трохи більше вводу, ніж суворо необхідно, але, як правило, лише кілька кілобайт:

  • headяк правило, зчитує шматки в кілька кілобайт (тому що це більш ефективно, ніж видача readсистемного виклику для кожного байту - така поведінка називається буферизацією), тому залишок останнього фрагменту після потрібного останнього рядка відкидається.
  • Можуть бути деякі дані під час транзиту, оскільки у труб є асоційований буфер, керований ядром (часто 512 байт). Ці дані будуть відкинуті.
  • grepможливо, накопичено деякі дані, готові стати вихідним фрагментом (знову буферизація). Він отримає SIGPIPE, коли він намагається очистити вихідний буфер.

Загалом система точно розроблена таким чином, що фільтруючі утиліти природно ведуть себе ефективно. Програми, які потребують продовження, коли їх вихідний канал відмирає, повинні зробити крок ігнорування сигналу SIGPIPE.


3

Сортоф, трубопровід працює так: він спочатку виконує першу команду, а потім другу команду у вашому випадку.

Тобто, давайте A|Bбуде дана команда. Тоді немає впевненості в тому Aабо Bпочинає першим. Вони можуть запуститися точно в той самий час, якщо є кілька процесорів. Труба може містити не визначений, але обмежений обсяг даних.

Якщо B намагається прочитати з труби, але даних немає, Bбуде чекати, поки дані надійдуть. Якщо ви Bчитали з диска, Bможе виникнути така ж проблема і потрібно почекати, поки читання диска закінчиться. Більш близькою аналогією було б читання з клавіатури. Там Bпотрібно буде чекати, коли користувач введе. Але у всіх цих випадках B розпочав операцію "читання" і повинен почекати, поки вона закінчиться. Але якщо Bкоманда така, що їй потрібен лише частковий вихід, Aто після певної точки, де Bдосягнутий рівень входу, Aбуде знищено SIGPIPE

Якщо Aнамагається записати на трубу, і труба заповнена, Aпотрібно зачекати, поки деяка кімната в трубі стане вільною. Aможе виникнути така ж проблема, якби він писав до терміналу. Термінал має контроль потоку і може поміркувати темп передачі даних. У будь-якому випадку, до A, він запустив операцію "запис" і буде чекати, поки операція запису завершиться.

Aі Bведуть себе як спільні процеси, хоча не всі спільні процеси будуть спілкуватися з трубою. Ніхто не повністю контролює інше.


1
Питання таке: "що робити A, коли B закриє свою сторону труби?"
enzotib

2
Хіба це не була би "труба"?
Паткос Чаба

1
Якщо програма намагається прочитати / записати з / у закриту трубку (наприклад, headвиходи), в програмі виникає сигнал SIGPIPE і поведінка за замовчуванням - це вихід.
Лекенштейн

Як саме це відповідає на питання? Здається , відповідь псусі коротша і більш суттєва .
jw013

1

grepне має прямого керування трубою (це лише отримання даних), і труба не має прямого контролю grep(це просто відправка даних) ...

Що grepчи будь-яка інша програма робить, цілком відповідає тій логіці програм. Якщо ви скажете grepчерез параметри командного рядка зробити ранній вихід, коли знайдеться , тоді він буде, інакше він буде чути до самого кінця файлу, шукаючи шаблон ...

Термінал також повністю від'єднаний від внутрішніх функцій grepта shellтрубних дій ... Термінал в основному є лише стартовим майданчиком та дисплеєм виходу ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.