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.
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
}
(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] #