Давайте вернемся к примеру с каналами, поскольку это весьма интересно, а также является хорошей иллюстрацией понятия ссылок. Когда вы используете канал в командной строке, 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] На самом деле существуют и другие различия между этими типами каналов. Но они выходят за рамки этой книги.