У якому порядку виконують трубопровідні команди?


89

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

Але я помітив, що коли люди шукають певний процес у ps, вони включають grep -v "grep" в кінці команди, щоб переконатися, що grep не відображається у кінцевому результаті. Це означає, що в команді ps aux | греп "баш" | grep -v "grep", що означає, що ps знав, що grep працює і тому знаходиться у виході ps. Але якщо ps закінчує працювати до того, як його результат перейде в греп, то як він знав, що grep працює?

flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY          TIME CMD
3773 pts/0    00:00:00 bash
3784 pts/0    00:00:00 ps
3785 pts/0    00:00:00 grep

чому б не прийняти відповідь?
törzsmókus

Відповіді:


64

Командні труби виконують одночасно. Коли ви запускаєтесь ps | grep …, то щастя жеребкування (або питання деталей роботи оболонки в поєднанні з плановою детальною налаштуванням глибоко в надрах ядра) в тому, psчи слід grepпочинати спочатку, і в будь-якому випадку вони продовжують виконувати одночасно.

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

grep pattern very-large-file | tr a-z A-Z

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

grep pattern very-large-file | head -n 1

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

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


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

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

3
@naxa Насправді два буфери. Всередині програми є буфер stdiogrep , а в самому каналі є буфер, яким керує ядро. Для останнього див. Як велика буферна труба?
Жиль

49

Порядок виконання команд насправді не має значення і не гарантується. Залишивши в стороні таємних деталі pipe(), fork(), dup()і execve(), оболонка спочатку створює трубу, трубопровід для даних , які будуть текти між процесами, а потім створює процеси з кінцями труби , з'єднаної з ними. Перший запущений процес може блокувати очікування на введення другого процесу або блокувати очікування другого процесу для початку зчитування даних з труби. Ці очікування можуть бути довільно довгими і не мають значення. Незалежно від того, в якому порядку виконуються процеси, дані з часом передаються і все працює.


5
Хороша відповідь, але ОП, здається, вважає, що процеси протікають послідовно. Ви можете зробити це зрозумілішим, що процеси проходять одночасно, і труба подібна .... трубі між відрами, куди вода протікає через усі приблизно (приблизно) одночасно.
Кіт

Дякую за роз’яснення. Джерела, які я читав, зробили враження, що трубові програми виконувались послідовно, а не одночасно.
action_potato

Щоб побачити досвід процесів, що починаються невизначеним чином, спробуйте виконати це 1000 разів: echo -na> & 2 | echo b> & 2
Ole Tange

28

Ризикуючи побити мертвого коня, здається, помилкове уявлення

    А | Б

еквівалентно

    A > тимчасовий файл 
    B < тимчасовий_файл 
    rm тимчасовий_файл

Але, коли було створено Unix і діти їхали динозаврів до школи, дисків було дуже мало, і зазвичай було досить доброякісною командою споживати весь вільний простір у файловій системі. Якби Bщось подібне , кінцевий вихід конвеєра міг би бути набагато меншим, ніж проміжний файл. Таким чином, труба була розроблена не як скорочення для « спочатку запуску А» , а потім запуску « В» із введенням з виходу « А », а як спосіб для одночасного виконання та усунення необхідності зберігання проміжного файлу на диску.grep some_very_obscure_stringBA


2
Це дає відповідь, чому і тому отримує мій голос.
LIttle Ancient Forest Kami

1

Зазвичай ви запускаєте це під bash. процес працює і починається одночасно, але працює паралельно оболонкою. Як це можливо?

  1. якщо це не остання команда в трубі, створіть неназвану трубу з парою розеток
  2. вилка
  3. у разі переназначення stdin / stdout у розетки, якщо це потрібно (для першого процесу в трубі stdin не перепризначається, те саме для останнього процесу та його stdout)
  4. у дочірній команді EXEC вказана команда з аргументами, які змітають вихідний код оболонки, але залишають усі відкриті ними сокети. ідентифікатор дочірнього процесу не буде змінено, оскільки це той самий дочірній процес
  5. одночасно з дочірнім, але паралельно під основною оболонкою переходять до кроку 1.

Система не гарантує, наскільки швидко буде виконано exec та запуститься задана команда. це незалежно від оболонки, але від системи. Це відбувається тому:

ps auxww| grep ps | cat

один раз покажіть grepта / або psкомандуйте, а наступний зараз. Це залежить від того, наскільки швидко ядро ​​дійсно запускає процеси за допомогою функції exec системи.


1
Одночасне виконання означає, що два або більше процесів виконуються в одних і тих же часових межах, як правило, з якоюсь залежністю між ними. Паралельне виконання означає, що два або більше процесів виконуються одночасно (наприклад, на окремих ядрах процесора одночасно). Паралелізм НЕ має відношення до питання, ні «як швидко» exec()виконується, але , як exec()дзвінки і виконання програм в трубі чергуватися .
Томас Найман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.