Bash:通过管道实现进程的相互交互

问题描述

环境:Linux/Docker,bash 版本 4.2。

问题:

  • server-app 通过交互式 shell 接受命令。
  • server-app 通过管道接收来自 client.sh 的命令。
  • server-app 写入 client.sh 收到的标准输出
  • client.sh 考虑 server-app输出以确定进一步的命令。
  • server-app 也可能要求输入密码 => 也就是说,终端的标准输入必须与 server-app输出一起转发到 client.sh

我使用 coproc 尝试了多种设置。但是,我要么陷入停滞状态,要么 没有收到数据。如何在 bash 中实现如下所示的设置?

                       .------>------------------------.
     .---------.       |         .------------.  stdin |       .-----------.
     | user    |-------'         | server-app |<-------+-------| client.sh |
     | console |<--+-------------|            |     .--------->|           |
     '---------'   |      stdout '------------'     |          '-----------'
                   '--------------------------------'

我的尝试:

coproc server.app

function expect { local expectation=$1
        # read from pipe until $expectation occurs in the input stream
        # when found,echo the line to 'stdout'
        echo "EXPECT: '$expectation'"
        while true; do
            read text <&"${copROC[0]}"
            if [[ "$text" == *"$expectation"* ]]; then
                    echo $text 
                    break
            fi
        done
}

function send { local command=$1
        # send $command through pipe 
        echo "SEND: $command"
        echo "$command" >&"${copROC[1]}"

}


expect "Conected to URL" 
send   "open"
expect "Session keepalive"
send   "session open"

# use the reported session identifier to setup the user command
session_n=$(expect "Identifier of Session created" | cut -d' ' -f5)    
command=$(echo "$user_command" | sed -e "s/SESSION/$session_n/g")

最后三行仅演示了 server-app 的可能处理 输出。这又有什么问题呢?怎样才能让它发挥作用。

解决方法

正如@sexpect 所提到的,解决问题的“自然”方法是expect。此工具将基于 Tcl 的脚本作为输入。

 spawn server-app

会在expect的控制下启动server-appexpect 也是这些脚本中的关键字。

 expect -re "something (..)"

等待与表达式 something (..) 匹配的输出。

 send ...

向应用程序发送一些字符。

expect_tty ...

从启动期望脚本的用户那里获取一些输入。