Заменить текущий процесс его сопроцессом / потомком

10

У меня есть программа, Pкоторая ожидает получить «Hello» и вывод «Почему?» перед предоставлением функции. Эта функция используется другими программами, которые не знают, что общение с «Hello» является обычной вежливостью. Таким образом, я хочу написать оболочку для Pэтого работает так (синтаксис zsh):

coproc P
print -p Hello  # Send Hello to P
read -pr line   # Read what P has to say
[[ "$line" = "Why?" ]] && Replace current process with the coprocess.
echo Could not get P's attention.

Использование catили ddв Replace...части (что-то вроде cat <&p &; exec cat >&p) приводит к ненужной буферизации. Какие у меня варианты?

Майкл
источник
Вы хотите zshрешение или bashрешение приемлемо?
Ройма
1
Я был бы разочарован bashрешением, которое не применимо zsh, но, безусловно, примет его »
Микаэль
Известно ли, какие другие программы будут запускать этот скрипт? Это конечный список, или это может быть любое число? Очевидно, что другая программа должна знать об этом, чтобы вызвать его.
Lizardx
Мое типичное использование было с sshи его вариантом ProxyCommand.
Михаэль
1
catкак правило, не буферизуется. Если это происходит в вашей системе, попробуйте cat -u.
Стефан Шазелас

Ответы:

1

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

Нет никакого способа сделать это напрямую (по крайней мере, в оболочке; внутри процесса dup2вызов может работать). Вам нужно будет склеить потоки. То есть:

( echo Hello ; cat ) | P | ( read ; cat )

Использование coprocкак в вашем примере тоже нормально. Обратите внимание, что команда сохраняет файловые дескрипторы в массив, и вы можете позже использовать их для перенаправлений.

Это не должно вызывать дополнительную буферизацию (по крайней мере, для GNU cat), если P не проверяет входные / выходные потоки, к которым он подключен, и не принимает решение о буферизации на основе этого. Например, стандартная библиотека C включит буферизацию на stdout/, stderrесли они подключены к файлу, но выполнит буферизацию строки, только если они подключены к терминалу.

Владимир Пантелеев
источник
-1

Можно протестировать с приведенным ниже кодом, используя Perl, чтобы избежать буферизации, попробуйте, если это работает для вас

Образец версии P

$ cat /tmp/P
#!/bin/bash
read input
if [[ $input = "Hello" ]]
then
    echo "Why?"
else
    exit 1
fi
echo "Got Hello from client, working ..."
sleep 10
echo "Need to read some input"
read x
echo "Got: $x"

Программа-обертка

$ cat /tmp/wrapper 
#!/usr/bin/zsh
coproc /tmp/P
print -p Hello  # Send Hello to P
read -pr line   # Read what P has to say
if [[ "$line" = "Why?" ]]; then
    perl -e '$|=1;print $_ while(<>);' <& p &
    perl -e '$|=1;print $_ while(<>);' >& p
else
    echo "Could not get P's attention."
fi

Тестовый забег

$ /tmp/wrapper 
Got Hello from client, working ...
Need to read some input
hi there P!   <== Typed in at teminal
Got: hi there P!
VenkatC
источник
Это то же самое, что и использование dd ibs=1, например. Я не в порядке с этим. В некотором смысле, у coproc есть своя собственная буферизация, и именно эту я хочу использовать.
Микаэль