bash中的IPC(使用命名管道,不使用expect)

时间:2015-07-23 08:11:35

标签: bash ipc named-pipes

我正在编写一个bash脚本,该脚本应该与现有(perl)程序进行交互(交互式)。不幸的是,我无法触及现有的perl程序,也无法使用expect

目前,该脚本与此stackoverflow回答Is it possible to make a bash shell script interact with another command line program?

的行一致

问题是(读:似乎是)perl程序在请求输入之前并不总是发送<newline>。这意味着命名管道上的bash while ... read没有&#34;得到&#34; (读取:显示)perl程序的输出,因为它一直在等待更多。至少这是我理解它的方式。

所以基本上perl程序正在等待输入,但是用户不知道,因为屏幕上没有任何内容。

所以我在bash脚本中所做的是关于

#!/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

这是有效的,除非perl程序正在执行类似

的操作
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";

然后只有bash脚本&#34;看到&#34;

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

但不是

    ? [C]

这不是最有问题的案例,而是最容易描述的案例。

有没有办法确保? [C]也被打印出来(我玩过cat <$readpipe &,但那确实没用?)

或者是否有更好的方法(鉴于我不能修改perl程序的限制,我也不能使用 expect)?

1 个答案:

答案 0 :(得分:3)

使用read -N1

让我们尝试下面的示例:与发送提示的程序交互(不是由换行符结束),我们的系统必须发送一些命令,接收发送的命令的echo。也就是说,子进程的总输出是:

$ cat example 
prompt> command1
prompt> command2

脚本可以是:

#!/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]

脚本现在是:

#!/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]
 ***