Различное поведение при использовании именованного канала с фоновым процессом - PullRequest
2 голосов
/ 18 марта 2019

Мне трудно понять именованные каналы.У меня есть следующий скрипт:

#!/bin/bash

function a_or_b {
   echo 'func begins'

   while true; do
      echo 'loop begins'

      read -s -n 1; echo $?
      case $REPLY in
         'a') return 0 ;;
         'b') return 1 ;;
      esac
   done

   echo 'func ends'
}

mkfifo pipe
a_or_b <pipe &

Теперь я ожидал, что этот скрипт будет делать:

  1. введите a_or_b и, следовательно, напечатайте func begin
  2. введите цикл и, следовательно, выведите loop begins
  3. прочитайте EOF из stdin и, следовательно, из pipe (поскольку я ничего не писал в pipe) и, следовательно, выведите 1, поскольку $?
  4. не совпадает ни с одним из условий, и поэтому вернитесь к шагу 2

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


Если я перенаправлю эхо в pipe до , вызов a_or_b:

...

mkfifo pipe
echo 'x' > pipe
a_or_b <pipe &

... скрипт не останавливается, и я могу продолжать вводить символы (включая a и 'b') в терминал безрезультатно.Поэтому мне нужно завершить сценарий, используя ^ C .


Если я перенаправлю echo в pipe после вызова a_or_b:

...

mkfifo pipe
a_or_b <pipe &
echo 'x' > pipe

... Я получаю следующий вывод:

func begins
loop begins
0
loop begins
0
loop begins
1
loop begins
1
loop begins
1

Это в основном то поведение, которое я ожидал от не повторения чего-либо до pipe.Функция начинается, заходит в цикл, читает символы x и \n из echo (что соответствует двум 0 s в выходных данных), а затем продолжает цикл навсегда, не читая никаких символов.И если я эхо a или b в канал, функция завершается.


Что вызывает все эти различные поведения?

1 Ответ

3 голосов
/ 18 марта 2019
a_or_b <pipe &

Перенаправления обрабатываются перед запуском команд.Оболочка блоков пытается открыть pipe для чтения.Со страницы руководства mkfifo (3) :

Открытие FIFO для обычного чтения блоков, пока какой-то другой процесс не откроет тот же FIFO для записи, и наоборот.

Оболочка не может продолжить работу, пока другой процесс не откроет FIFO для записи.Только тогда он завершит настройку перенаправления и фактически вызовет a_or_b.


echo 'x' > pipe
a_or_b <pipe &

К сожалению, это имеет ту же, но обратную проблему.Оболочка не может пройти после перенаправления > pipe, пока другой процесс не откроет FIFO для чтения.Он никогда не попадет ни на echo, ни на вторую строку, которая будет считываться из канала.


a_or_b <pipe &
echo 'x' > pipe

Надеемся, теперь вы можете понять, почему эта версия работает.Фоновая оболочка пытается прочитать из трубы и блоков.Оболочка переднего плана, отдельный процесс, пишет в нее.Ага!Два процесса открыли канал, один для чтения и один для записи.Теперь они оба могут продолжить.Птицы поют, и все счастливы.

...