Как понимать трубы

21

Когда я просто использовал pipe в bash, я больше не думал об этом. Но когда я читаю некоторый пример кода на языке C, используя системный вызов pipe () вместе с fork (), я удивляюсь, как понимать каналы, включая как анонимные каналы, так и именованные каналы.

Часто говорят, что «все в Linux / Unix - это файл». Интересно, является ли канал на самом деле файлом, так что одна часть, которую он соединяет, записывает данные в файл канала, а другая часть читает из файла канала? Если да, где создается файл канала для анонимного канала? В / tmp, / dev или ...?

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

Тим
источник

Ответы:

23

Что касается вашего вопроса производительности, каналы более эффективны, чем файлы, потому что дисковый ввод-вывод не требуется. Так cmd1 | cmd2является более эффективным , чем cmd1 > tmpfile; cmd2 < tmpfile(это может не быть правдой , если tmpfileподдерживается на диске RAM или другого устройства памяти как именованный канал, но если это именованный канал, cmd1должен работать в фоновом режиме , как его выход может блокировать , если труба заполняется ). Если вам нужен результат cmd1и все еще нужно отправить его вывод cmd2, вы должны cmd1 | tee tmpfile | cmd2разрешить cmd1и cmd2запускать параллельно, избегая операций чтения с диска cmd2.

Именованные каналы полезны, если многие процессы читают / пишут в один и тот же канал. Они также могут быть полезны, когда программа не предназначена для использования stdin / stdout для своих операций ввода-вывода, нуждающихся в использовании файлов . Я поместил файлы курсивом, потому что именованные каналы не являются файлами с точки зрения хранения, поскольку они находятся в памяти и имеют фиксированный размер буфера, даже если они имеют запись в файловой системе (для справочных целей). У других вещей в UNIX есть записи файловой системы, не являющиеся файлами: просто представьте себе /dev/nullили другие записи в /devили /proc.

Поскольку каналы (именованные и безымянные) имеют фиксированный размер буфера, операции чтения / записи в них могут блокироваться, в результате чего процесс чтения / записи переходит в состояние IOWait. Кроме того, когда вы получаете EOF при чтении из буфера памяти? Правила этого поведения хорошо определены и могут быть найдены в человеке.

Одна вещь, которую вы не можете сделать с каналами (именованными и безымянными), это поиск в данных. Поскольку они реализованы с использованием буфера памяти, это понятно.

О "everything in Linux/Unix is a file", я не согласен. Именованные каналы имеют записи файловой системы, но не являются точно файловыми. Безымянные каналы не имеют записей файловой системы (кроме, может быть, в /proc). Однако большинство операций ввода-вывода в UNIX выполняются с использованием функции чтения / записи, для которой требуется файловый дескриптор , включая безымянный канал (и сокет). Я не думаю, что мы можем сказать это "everything in Linux/Unix is a file", но мы, конечно, можем сказать это "most IO in Linux/Unix is done using a file descriptor".

jfg956
источник
Благодарность! Две команды, соединенные параллельным каналом, вместо второй начинают выполняться после завершения первой?
Тим
Да, 2 команды выполняются параллельно. Если бы они не были и 1-й вывод больше, чем буфер, он был бы заблокирован. Вы можете попробовать это, запустив cmd1 > fifoи cmd2 < fifoв 2 разных оболочках, создав именованный канал с помощью mkfifo fifo.
jfg956
Другой тест, который вы можете сделать, это убить, cmd2пока cmd1он еще работает: cmd1вероятно, перестанет сообщать о сообщении о сломанной трубе.
jfg956
Благодарность! что ты имеешь ввиду будет заблокирован? Если это происходит, означает ли это, что дата в потоке после блока будет потеряна?
Тим
2
Данные не потеряны. Если буфер канала заполнен, cmd1запись в канал будет возвращена только тогда, когда cmd2будут прочитаны данные из канала. Таким же образом cmd2чтение из канала будет блокироваться, если буфер пуст до cmd1записи в канал.
jfg956
4

Двумя основными принципами философии UNIX являются

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

    Использование конвейеров позволяет использовать эффекты этих двух
    основных принципов проектирования для создания чрезвычайно мощных цепочек команд для достижения желаемого результата.

    Большинство программ командной строки, которые работают с файлами, могут также принимать ввод по стандартному входу (ввод с клавиатуры) и выводить к стандартному выводу (печать на
    экране).

    Некоторые команды предназначены для работы только внутри канала и не могут работать с файлами напрямую.

    например trкоманда

  ls -C | tr 'a-z' 'A-Z'
    cmd1 | cmd2
  • Посылает STDOUT cmd1 в STDIN cmd2 вместо экрана.

  • STDERR не передается через трубы.

    Короче Pipes is character (|)можете подключать команды.

    Любая команда, которая пишет в STDOUT, может быть использована в левой части канала.

       ls - /etc | less 

    Любая команда, которая читает из STDIN, может использоваться с правой стороны канала.

       echo "test print" | lpr 

    Традиционный канал является «неназванным», потому что он существует анонимно и сохраняется только в течение всего процесса. Именованный канал является системно-постоянным и существует за пределами жизненного цикла процесса и должен быть удален, когда он больше не используется. Процессы обычно подключаются к именованному каналу (обычно появляющемуся в виде файла) для выполнения межпроцессного взаимодействия (IPC).

источник: http://en.wikipedia.org/wiki/Named_pipe

mr_eclair
источник
3

Чтобы дополнить другие ответы ...

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

user606723
источник
1

Все это файл.

Если мы будем понимать фразу слишком буквально, мы получим значение «у нас есть только файлы и ничего больше». Это не правильная интерпретация, ну и что.

Когда мы говорим «Все это файл», мы не говорим, что все хранится на диске. Мы говорим, что все выглядит как файл, может быть прочитано, может быть записано.

В Unix, если файл или не-файл открыт, его можно рассматривать как файл. Однако не все файлы поддерживают все операции. Например, некоторые файлы (которые не являются файлами) не поддерживают поиск: они должны быть прочитаны / записаны последовательно (это верно для каналов и сокетов).

У всего есть имя файла (в некоторых системах: например, Debian Gnu / Linux и многие другие Gnu / Linux).

  • Все открытые файлы получают имя файла. Видеть/proc/self/fd/…
  • Сетевые сокеты могут быть открыты с именем файла, см., /dev/tcp
    Например,cat </dev/tcp/towel.blinkenlights.nl/23
Ctrl-Alt-Делор
источник
Эта последняя часть действительна только в системах с /procфайловой системой и в системах (или оболочках), которые предоставляют /dev/tcpфайловую структуру.
Кусалананда