shell dynamically answer to terminal prompt

空扰寡人 提交于 2019-12-11 10:29:54

问题


questions.sh

#!/bin/bash

declare -a animals=("dog" "cat")
declare -a num=("1" "2" "3")

for a in "${animals[@]}"
do
    for n in "${num[@]}"
    do
        echo "$n $a ?"
        read REPLY
        echo "Your answer is: $REPLY"
    done
done

responder.sh

#!/usr/bin/expect -f

set timeout -1

spawn ./questions.sh

while true {

    expect {
        "*dog*" { send -- "bark\r" }

        "^((?!dog).)*$" { send -- "mew\r" }
    }


}

expect eof

running: './responder.sh'

expected outcome:

1 dog ?
bark
Your answer is: bark
2 dog ?
bark
Your answer is: bark
3 dog ?
bark
Your answer is: bark
1 cat ?
mew
Your answer is: mew
2 cat ?
mew
Your answer is: mew
3 cat ?
mew
Your answer is: mew

actual outcome: hang at 'cat' question and not responding...

1 dog ?
bark
Your answer is: bark
2 dog ?
bark
Your answer is: bark
3 dog ?
bark
Your answer is: bark
1 cat ?

tried and searched multiple ways but still not working. thank you very much.


回答1:


The expect program hangs because you match the first "dog", send bark, then you expect eof with an infinite timeout. Of course you don't have "eof" because the shell script is waiting for input.

You need to use the exp_continue command for your loops, not while:

#!/usr/bin/expect -f
set timeout -1
spawn ./questions.sh
expect {
    -re {dog \?\r\n$}        { send -- "bark\r"; exp_continue }
    -re {(?!dog)\S+ \?\r\n$}  { send -- "mew\r";  exp_continue }
    eof
}

I made the patterns much more specific: either "dog" or "not dog" followed by a space, question mark and end-of-line characters.

The exp_continue commands will keep the code looping within the expect command until "eof" is encountered.


We can make the pattern a little DRYer:

expect {
    -re {(\S+) \?\r\n$} { 
        if {$expect_out(1,string) eq "dog"} then {send "bark\r"} else {send "mew\r"} 
        exp_continue 
    }
    eof
}



回答2:


(This is not a direct answer to your question. Just FYI.)

You can write Expect-like scripts with shell code only. For your example:

The question.sh:

[STEP 109] # cat question.sh
declare -a animals=("dog" "cat")
declare -a num=("1" "2" "3")

for a in "${animals[@]}"
do
    for n in "${num[@]}"
    do
        echo "$n $a ?"
        read REPLY
        echo "Your answer is: $REPLY"
    done
done

The responder.sh:

[STEP 110] # cat responder.sh
export SEXPECT_SOCKFILE=/tmp/qa.sock
sexpect spawn bash question.sh

while true; do
    sexpect expect -cstring -re '(dog|cat) [?][\r\n]+'
    ret=$?
    if [[ $ret == 0 ]]; then
        anim=$(sexpect expect_out -index 1)
        if [[ $anim == dog ]]; then
            sexpect send -cstring 'bark\r'
        else
            sexpect send -cstring 'meow\r'
        fi
    else
        if ! sexpect chkerr -errno $ret -is eof; then
            sexpect close
        fi
        sexpect wait
        break
    fi
done

Run it:

[STEP 111] # bash responder.sh
1 dog ?
bark
Your answer is: bark
2 dog ?
bark
Your answer is: bark
3 dog ?
bark
Your answer is: bark
1 cat ?
meow
Your answer is: meow
2 cat ?
meow
Your answer is: meow
3 cat ?
meow
Your answer is: meow
[STEP 112] #


来源:https://stackoverflow.com/questions/50279032/shell-dynamically-answer-to-terminal-prompt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!