I have a program P that expects to receive "Hello" and output "Why?" before providing a feature. This feature is used by other programs that are not aware that it is common courtesy to start a conversation with "Hello". I thus want to write a wrapper for P that works like this (zsh syntax):

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.

Using cat or dd in the Replace... part (something like cat <&p &; exec cat >&p) results in unnecessary buffering. What are my options?

  • Do you want a zsh solution or is a bash solution acceptable? – roaima Nov 17 '15 at 9:47
  • 1
    I'd be disappointed by a bash solution that is not applicable in zsh, but would certainly accept it ☺ – Michaël Nov 17 '15 at 13:43
  • Is it known what other programs would be running this script? Is it a finite list, or could it be any number? Clearly the other program needs to know about this one in order to call it. – Lizardx Nov 17 '15 at 21:25
  • My typical use was with ssh and its option ProxyCommand. – Michaël Nov 18 '15 at 4:58
  • 1
    cat generally doesn't buffer. If it does on your system, try cat -u. – Stéphane Chazelas Jan 7 '16 at 17:06

The problem you've stated isn't really about replacing a process, but replacing an existing process's streams. The goal is to interact a bit with the process then hand over its input/output to another pair of connected streams.

There is no way to do this directly (at least, in the shell; inside the process, a dup2 call might conceivably work). You will need to splice the streams. I.e:

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

Using coproc as in your example is OK too. Note that the command saves the file descriptors to an array, and you can later use them for redirections.

This should not cause additional buffering (at least with GNU cat), unless P inspects the input/output streams it's connected to and makes a decision to buffer based on that. For example, the C standard library will enable buffering on stdout/stderr if they are connected to a file, but only perform line buffering if they're connected to a terminal.


Able to test with below code using perl to avoid buffering, try if this works for you

Sample version of P

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

The wrapper program

$ cat /tmp/wrapper 
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
    echo "Could not get P's attention."

Test run

$ /tmp/wrapper 
Got Hello from client, working ...
Need to read some input
hi there P!   <== Typed in at teminal
Got: hi there P!
  • This is the same as using dd ibs=1, for instance. I'm not fine with this. In a way, the coproc has its own buffering, and it is this one that I want to use. – Michaël Nov 18 '15 at 5:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.