IPC in bash (using named pipes that don't use expectations)

I am writing a bash script that should interact (interactively) with an existing (perl) program. Unfortunately, I cannot touch the existing perl program and cannot use expect .

Currently the script runs along the lines of this stackoverflow answer. Is it possible to associate a bash script shell with another command line program?

The problem is that the perl program does not always send <newline>before an input request. This means that bash while ... readin the named pipe does not "receive" (read: display) the output of the perl program because it continues to wait for more. At least, as I understand it.

So, basically the perl program is waiting for input, but the user does not know, because nothing is displayed on the screen.

So what I do in a bash script is roughly

#!/bin/bash

mkfifo $readpipe
mkfifo $writepipe

[call perl program] < $writepipe &> $readpipe &
exec {FDW}>$writepipe
exec {FDR}<$readpipe

...

while IFS= read -r L
do
    echo "$L"
done < $readpipe

This works if the perl program does not do something like

print "\n";
print "Choose action:\n";
print "[A]: Action A      [B]: Action B\n";
print " [C]: cancel\n";
print "    ? ";
print "[C] ";
local $SIG{INT}  = 'IGNORE';
$userin = <STDIN> || ''; chomp $userin;
print "\n";

Then the bash script only "sees"

Choose action:
[A]: Action A      [B]: Action B
 [C]: cancel

but not

    ? [C]

This is not the most problematic case, but one that is easiest to describe.

Is there a way to make sure that it prints ? [C](I played with cat <$readpipe &, but it really didn't work)?

Or is there a better approach for everyone (given the limitation that I cannot change the perl program, and I cannot use expect)?

+4
source share
1 answer

Use read -N1.

: , ( ), , . :

$ cat example 
prompt> command1
prompt> command2

script :

#!/bin/bash 
#

cat example | while IFS=$'\0' read -N1 c; do
  case "$c" in
  ">") 
       echo "received prompt: $buf" 
        # here, sent some command
       buf=""
       ;;
  *)
      if [ "$c" == $'\n' ]; then
        echo "received command: $buf"
        # here, process the command echo
        buf=""
      else
        buf="$buf$c"
      fi
      ;;
  esac
done

:

received prompt: prompt
received command:  command1
received prompt: prompt
received command:  command2

:

$cat example

Choose action:
[A]: Action A      [B]: Action B
[C]: cancel
    ? [C]

script :

#!/bin/bash 
#

while IFS=$'\0' read -N1 c; do
  case "$c" in
  '?') 
       echo "*** received prompt after: $buf$c ***" 
       echo '*** send C as option ***'
       buf=""
       ;;
  *)
      buf="$buf$c"
      ;;
  esac
done < example

echo "*** final buffer is: $buf ***"

:

*** received prompt after: 
Choose action:[A]: Action A      [B]: Action B
[C]: cancel
    ? ***
*** send C as option ***
*** final buffer is:  [C]
 ***
+3

Source: https://habr.com/ru/post/1599245/


All Articles