Анонимные” Каналы и Именованные Каналы

Давайте вернемся к примеру с каналами, поскольку это весьма интересно, а также является хорошей иллюстрацией понятия ссылок. Когда вы используете канал в командной строке, shell создает для вас канал и работает таким образом, что команда перед каналом пишет в него, а команда после трубы читает из канала. В данном случае мы наблюдаем неименованный канал (например такой как используется в shell) или именованный (смотрите выше) действительно похож на FIFO (First In, First Out (Кто первым вошел, тот первым вышел)). Мы уже приводили пример того, как используются каналы в shell, но давайте в для более глубокого понимания выполним еще одну демонстрацию:

$ ls -d /proc/[0-9] | head -5
/proc/1/
/proc/2/
/proc/3/
/proc/4/
/proc/5/

В приведенном примере есть одна вещь, которую вы наверняка не заметили (потому что это происходит слишком быстро для того чтобы быть заметным). состоящая в том, что записи на каналах блокируются. Это означает, что во время выполнения команды ls, запись в канал блокируется до тех пор, пока процесс с другой стороны канала (в данном случае head) не прочитает канал. Чтобы визуализировать этот эффект, можно создавать именованные каналы, которые, в отличии от используемых shell, имеют имена (то есть на них существуют ссылки). [19] Для создания именованного канала используется команда mkfifo:

$ mkfifo a_pipe
$ ls -il
total 0
    169 prw-rw-r--    1 queen     queen        0 Dec 10 14:12 a_pipe|
  #
  # вы видите что счетчик ссылок показывает 1, результат ls
  # показывает что файл является каналом ('p').
  #
  # Также можно создать ссылку с помощью ln
  #
$ ln a_pipe the_same_pipe
$ ls -il
total 0
    169 prw-rw-r--    2 queen     queen        0 Dec 10 15:37 a_pipe|
    169 prw-rw-r--    2 queen     queen        0 Dec 10 15:37 the_same_pipe|
$ ls -d /proc/[0-9] >a_pipe
  #
  # Процесс заблокировался, так как никто не читает канал с другой стороны.
  # Чтобы приостановить процесс нажмите Ctrl+z
  #
zsh: 3452 suspended  ls -d /proc/[0-9] > a_pipe
  #
  # ...теперь отошлем процес в фоновый режим (background):
  #
$ bg
[1]  + continued  ls -d /proc/[0-9] > a_pipe
  #
  # а теперь почитаем из канала...
  #
$ head -5 <the_same_pipe
  #
  # ...процесс записи прервался....
  #
[1]  + 3452 done       ls -d /proc/[0-9] > a_pipe
/proc/1/
/proc/2/
/proc/3/
/proc/4/
/proc/5/
#

Кстати, точно также можно заблокировать и чтение. Если выполнить приведенные выше команды в обратном порядке, мы увидим что команда head блокируется, в ожидании пока какой-нибудь процесс не выполнит чтение:

$ head -5 <a_pipe
  #
  # Программа заблокировалась, Для того чтобы приостановить : Ctrl+z
  #
zsh: 741 suspended  head -5 < a_pipe
  #
  # отправляем в фоновое выполнение...
  #
$ bg
[1]  + continued  head -5 < a_pipe
  #
  # ...ну и теперь покормите немножко этот канал :)
  #
$ ls -d /proc/[0-9] >the_same_pipe
$ /proc/1/
/proc/2/
/proc/3/
/proc/4/
/proc/5/
[1]  + 741 done       head -5 < a_pipe
$

В предыдущем примере присутствует один нежелательный эффект: команда ls прерывается до того как команда head получила данные. Поэтому получается, что это действие нельзя выполнить без выполнения промежуточных действий в командной строке.



[19] На самом деле существуют и другие различия между этими типами каналов. Но они выходят за рамки этой книги.