Reemplazar el proceso actual por su coproceso / hijo

10

Tengo un programa Pque espera recibir "Hola" y mostrar "¿Por qué?" antes de proporcionar una función. Esta función es utilizada por otros programas que no son conscientes de que es una cortesía común iniciar una conversación con "Hola". Por lo tanto, quiero escribir un contenedor para Pque funcione así (sintaxis 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.

Usar cato dden la Replace...parte (algo así como cat <&p &; exec cat >&p) da como resultado un almacenamiento en búfer innecesario. ¿Cuáles son mis opciones?

Miguel
fuente
¿Quieres una zshsolución o es una bashsolución aceptable?
roaima
1
Me decepcionaría una bashsolución que no es aplicable zsh, pero que ciertamente la aceptaría ☺
Michaël
¿Se sabe qué otros programas ejecutarían este script? ¿Es una lista finita, o podría ser cualquier número? Claramente, el otro programa necesita saber sobre este para poder llamarlo.
Lizardx
Mi uso típico era con sshy su opción ProxyCommand.
Michaël
1
catgeneralmente no amortigua. Si lo hace en su sistema, intente cat -u.
Stéphane Chazelas

Respuestas:

1

El problema que ha declarado no se trata realmente de reemplazar un proceso , sino de reemplazar las secuencias de un proceso existente . El objetivo es interactuar un poco con el proceso y luego entregar su entrada / salida a otro par de flujos conectados.

No hay forma de hacer esto directamente (al menos, en el shell; dentro del proceso, una dup2llamada podría funcionar). Tendrá que empalmar las corrientes. Es decir:

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

Usar coproccomo en su ejemplo también está bien. Tenga en cuenta que el comando guarda los descriptores de archivo en una matriz, y luego puede usarlos para redireccionamientos.

Esto no debería causar almacenamiento en búfer adicional (al menos con GNU cat), a menos que P inspeccione los flujos de entrada / salida a los que está conectado y tome la decisión de usar el búfer en función de eso. Por ejemplo, la biblioteca estándar de C habilitará el almacenamiento en búfer en stdout/ stderrsi están conectados a un archivo, pero solo realizará el almacenamiento en búfer de línea si están conectados a un terminal.

Vladimir Panteleev
fuente
-1

Capaz de probar con el siguiente código usando Perl para evitar el almacenamiento en búfer, pruebe si esto funciona para usted

Versión de muestra de 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"

El programa envoltorio

$ 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

Prueba de funcionamiento

$ /tmp/wrapper 
Got Hello from client, working ...
Need to read some input
hi there P!   <== Typed in at teminal
Got: hi there P!
VenkatC
fuente
Esto es lo mismo que usar dd ibs=1, por ejemplo. No estoy bien con esto. En cierto modo, el coproc tiene su propio almacenamiento en búfer, y es este el que quiero usar.
Michaël