как перенаправить стандартный вывод 2-го процесса обратно в стандартный вывод первого процесса? - PullRequest
17 голосов
/ 26 февраля 2011

У меня есть два процесса, которые мне нужно соединить так:

proc1 - отправляет вывод в proc2 proc2 - отправляет вывод в proc1

До сих пор все примеры труб были такого рода: proc1 | proc2

Это хорошо, но как мне заставить вывод proc2 перейти на proc1?

Пример bash был бы хорош. Пример с оболочкой Windows был бы великолепен:)

Спасибо заранее, Адриан.

Добавление более подробной информации:

Ожидается, что система будет работать как система клиент-сервер, в которой клиент работает с сервером в модели взаимодействия запрос-ответ. Взаимодействие заканчивается, когда у клиента больше нет запросов.

Пример взаимодействия: клиент: request1; сервер: response1; клиент: request2; сервер: response2; , , , , клиент: closeRequest; сервер: closeApproved;

В этот момент сервер завершает работу после выхода из клиента. Конец примера.

Похоже, что решение вроде (при условии наличия трубы) клиент <труба | сервер> труба не будет работать (пожалуйста, исправьте меня), потому что в этом случае клиент выдает один большой запрос, оболочка направляет этот большой запрос серверу, затем сервер выдает один большой ответ, и, наконец, оболочка передает этот большой ответ клиенту.

Ответы [ 5 ]

17 голосов
/ 27 февраля 2011

Похоже, что bash сопроцесс может быть тем, что вы хотите. Посмотрите зарезервированное слово coproc в руководстве по bash.


(Изменить: добавление простой схемы использования)

Работает так:

# start first process as a coprocess to the current shell
coproc proc1

# now ${COPROC[0]} contains the number of an open (input) file descriptor
# connected to the output of proc1, and ${COPROC[1]} the number of an
# open (output) file descriptor connected to the input of proc1.


# start second process, connecting its input- and outputstreams
# to the output- and inputstreams of the first process
proc2 <&${COPROC[0]} >&${COPROC[1]}

# wait on the first process to finish.
wait $COPROC_PID

Если у вас может быть несколько сопроцессов, дайте вашему процессу имя, подобное этому:

coproc NAME {
    proc1
}

Тогда вы можете использовать NAME везде, где раньше использовался COPROC.


Вот полный пример программы, использующей функцию ping в качестве proc1 и proc2:

#!/bin/bash
#
# Example program using a bash coprocess to run two processes
# with their input/output streams 
#


#
# A function which reads lines of input and
# writes them back to standard output with the
# first char cut off, waiting 5s inbetween.
#
# It finishes whenever an empty line is read or written,
# or at end-of-file.
#
# The parameter $1 is used in debugging output on stderr.
#
function ping ()
{
    while read 
    do
        local sending
        echo "ping $1: received '$REPLY'" >&2
        [[ -n $REPLY ]] || break
        sleep 5s
        sending=${REPLY:1}
        echo "ping $1: sending '$sending'"  >&2
        echo $sending
        [[ -n $sending ]] || break
    done
    echo "ping $1: end" >&2
}

#
# Start first ping process as a coprocess with name 'p1'.
#

coproc p1 {
    ping 1
}

# send some initial data to p1. (Not needed if one of the processes
# starts writing before first reading.)
echo "Hello World" >&${p1[1]}
sleep 2.5s

#
# Run second ping process, connecting its default input/output
# to the default output/input of p1.
# 
ping 2 <&${p1[0]} >&${p1[1]}

# wait for the coprocess to finish too.
wait $p1_PID

Он использует два вызова функции оболочки вместо внешних программ, но он также будет работать с такими программами. Вот вывод (на stderr):

ping 1: received 'Hello World'
ping 1: sending 'ello World'
ping 2: received 'ello World'
ping 2: sending 'llo World'
ping 1: received 'llo World'
ping 1: sending 'lo World'
ping 2: received 'lo World'
ping 2: sending 'o World'
ping 1: received 'o World'
ping 1: sending ' World'
ping 2: received 'World'
ping 2: sending 'orld'
ping 1: received 'orld'
ping 1: sending 'rld'
ping 2: received 'rld'
ping 2: sending 'ld'
ping 1: received 'ld'
ping 1: sending 'd'
ping 2: received 'd'
ping 2: sending ''
ping 2: end
ping 1: received ''
ping 1: end
11 голосов
/ 26 февраля 2011

Вот пример bash, использующий echo для предоставления некоторого начального ввода и именованный канал для обеспечения обратной связи:

mkfifo fifo
echo "fifo forever" | cat - fifo | tee fifo
  • proc1 (cat) принимает данные от stdin и fifo
  • proc2 (tee) передает вывод на стандартный вывод и fifo
6 голосов
/ 27 ноября 2012

Это пример, показывающий, что вы хотите, с двумя процессами, которые оба принимают один аргумент:

mkfifo fifo
./process1 argument1 < fifo | ./process2 argument1 > fifo

Сначала мы создаем именованный канал с именем fifo в текущем каталоге. Затем мы выполняем process1 с fifo в качестве ввода, выход которого будет проходить через анонимный канал | к входу process2, выход которого перейдет в fifo, закрывая цикл.

После выхода из обоих процессов вы должны удалить канал, так же, как вы удаляете обычный файл:

rm fifo
1 голос
/ 19 мая 2011
#!/bin/bash

fifo=$(/bin/mktemp -u)
/usr/bin/mkfifo $fifo

# register resources cleanup trap
trap "/bin/unlink $fifo" INT TERM EXIT

# start a background shell redirecting its output to the pipe
(for ((i=0; i < 5; ++i)); do echo "pam pam, i = $i"; sleep 1; done ) 1> $fifo&

# read the output of the background shell from the pipe
while read line 0< $fifo; do
  echo "param $line"
done

# wait for child process to terminate
wait
0 голосов
/ 26 февраля 2011

В большинстве оболочек это трудно сделать, и на то есть веская причина - очень просто заблокировать ваши программы, когда каждая из них ожидает ввода от другой.Можете ли вы рассказать нам больше о том, какую информацию вы пытаетесь передать?Если вы просто пытаетесь создать RPC-подобную систему, вам, вероятно, следует использовать библиотеку, предназначенную для этого.

...