Can't run an expect script: invalid command name "Yes/No" - expect

I have this expect script that need to execute some other shell script to accept a Licence agreement
#!/usr/bin/expect
spawn ./xxx.sh
expect -ex "--More--"
send -- " "
expect "Do you agree with this license ?[Yes/No]"
send "Y\r"
But when I run it I get this error
invalid command name "Yes/No"
while executing
"Yes/No"
invoked from within
"expect "Do you agree with this license ?[Yes/No]""
(file "./xxx.sh" line 5)
I don't know what I'm doing wrong

expect is an extension of the Tcl language. In Tcl, you use square brackets for command substitution. Like the bash shell, command substitution occurs within double quoted strings.
To prevent your code from attempting to execute the Yes/No command:
use different quotes: Tcl uses curly braces as the non-interpolating quotes:
expect {Do you agree with this license ?[Yes/No]}
escape the brackets to prevent command substitution:
expect "Do you agree with this license ?\[Yes/No\]"

Related

Expect does not detect string

I need to automate the input of a string in a command called from a shell (sh) script, using expect To accomplish this I have:
#!/bin/sh
MY_ARGS="-a -b -c" expect -c "
spawn mycommand $MY_ARGS
expect 'continue, I know what I am doing' { send -- 'continue, I know what I am doing\r' }
expect eof"
The mycommand output is:
Enter "continue, I know what I am doing" to use the outdated data anyway:
But the string is not being detected and therefore nothing is sent. What is wrong with the expect command?
Thanks.
There's a few things going on here:
When you write var=value some_command, then $var is set in the environment for the command.
Inside expect you need $env(MY_ARGS)
But now you have a quoting problem, you can't put the expect body in double quotes because you
don't want the shell to expand that variable.
#sexpect_Expect.for.Shells is right, single quotes are not special in Tcl (and hence expect). expect sees this:
expect {
{'continue,} {I}
{know} {what}
{I} {am}
{doing'} { send -- "'continue," "I" "know" "what" "I" "am" "doing\r'" }
}
To solve the quoting problems, I recommand using a quoted heredoc in the shell
export MY_ARGS='-a -b -c'
# .......v..........v these quotes are crucial
expect <<'END_EXPECT'
set phrase "continue, I know what I am doing"
set timeout -1
spawn mycommand {*}$env(MY_ARGS)
expect $phrase
send -- "$phrase\r"
expect eof
END_EXPECT
Note how I expanded the env variable: {*}$env(MY_ARGS) -- the {*} syntax splits the variable content into separate words.

How to get the command output in variable?

I executed the below code as .sh file and getting the result as expected. Now I need to store the output of the "send" command and do things further.
I have done the below bash code and now I am keeping the output in a file:
#!/usr/bin/expect -f
spawn iroot
expect ".* password for"
sleep 3
send "password\r"
sleep 5
send "dmidecode -t system | grep Manufacturer > /tmp/manfacdetails.txt\r"
send "exit\r"
interact
How can I do that?
It seems that you are using iroot to obtain root access to a phone and issuing a command as root.
I am assuming here that the command you already have is noninteractive, and produces the output you want if you take out the redirection to a file, without any human interaction.
Then, the simple matter of capturing its output is covered by the common FAQ How to set a variable to the output of a command in Bash?
#!/bin/bash
manufacturer=$(expect <<\____HERE)
spawn iroot
expect ".* password for"
sleep 3
send "password\r"
sleep 5
send "dmidecode -t system | grep Manufacturer\r"
send "exit\r"
interact
____HERE
if [ "$manufacturer" = "Motor Ola" ]; then
ola=1
fi
# Maybe you'll prefer case over if, though
case $manufacturer in
"Samsung" | "LG" ) korean=1 ;;
"Apple")
echo "$0: You're kidding, right?" >&2
exit 127;;
*) echo "$0: Unknown manufacturer $manufacturer" >&2
exit 1;;
esac
If this doesn't work for you then Use expect in bash script to provide password to SSH command has some variants you might want to try.
You also seem to be confused about the nature of scripts. Any executable file which has a shebang as its first line will be executable by whatever interpreter is specified there. Mine has /bin/bash so this is a shell script and more specifically a Bash script, while yours has expect as its interpreter, so it's an Expect script. You also commonly have Awk scripts and Perl scripts and Python scripts (and less commonly but not at all uncommonly scripts in many, many other languages).
As already mentioned, Expect is also a scripting language, and it is possible that you would like for yours to remain an Expect script, rather than a shell script with an embedded Expect script snippet. Perhaps then see expect: store output of a spawn command into variable
The name of the file which contains the script can be anything, but the standard recommendation is to not give it an extension -- Unix doesn't care, and human readers will be confounded if your .sh file is an Expect script (as it currently is).
Perhaps tangentially see also Difference between sh and bash as well as http://shellcheck.net/ which you can use to diagnose syntax errrors in your (shell) scripts.

Expect script not working and send status getting skipped

I have written a script to execute a setup on the server, but while executing send statement is getting skipped and other one getting executed.
Below is my script :
enter code here[code written][1]
====================ERROR m getting=============================
Enter the name of the new namespace you want to create [coe_ns] :
Enter the name of the clearinghouse you want to create [coe_ch] : invalid command name "C"
while executing
"C"
invoked from within
"expect -re "* Option to execute (Continue/Restart/Quit) [C]: $""
(file "./TNS_Server_Setup.sh" line 21)
I have a doubt that send command before that is not getting executed, also am I passing "ENTER" right way.
expect uses square brackets as the command substitution syntax (in the same way that the shell uses backticks or $(...). So when you write
expect -re "* Option to execute (Continue/Restart/Quit) [C]: $"
expect sees [C] and tries to invoke the command C.
Also, that standalone * will throw a "quantifier operand invalid" error, because that's a special character for regular expressions. You either need to escape it or remove it from the expression.
Use a different quoting mechanism that inhibits command substitution (like in the shell where you'd use single quotes)
expect -re {Option to execute (Continue/Restart/Quit) [C]: $}
You did not include your code in the question so we can't see your send command, but to "just hit enter", you would send "\r"
Update:
If you need to match multiple things, the expect command can do that: give it a list of pattern action pairs. Expect will match any of them.
expect {
-re {Option to execute (Continue/Restart/Quit) [C]: $} {
send "\r"
exp_continue
}
-re {enter the datatype $} {
send "array\r"
exp_continue
}
"some pattern that denotes we're done"
}

Mac OS Expect Command for Profile Removal

We are replacing the profile we use for our company, and we need to run a command to remove the old profiles.
/usr/bin/profiles -D
it asks for input from the user "Are you sure you want to delete all configuration profiles? [y/n]:"
We are trying to automate this process, and have looked into the expect command but are having trouble getting it to run.
/usr/bin/expect -f - <<EOD
spawn /usr/bin/profiles -D
expect "Are you sure you want to delete all configuration profiles? [y/n]:"
send "y\n"
EOD
But we get this error when we try and run it.
sudo /Users/gpmacarthur/Desktop/test.sh
spawn /usr/bin/profiles -D
invalid command name "y/n"
while executing
"y/n"
invoked from within
"expect "Are you sure you want to delete all configuration profiles? [y/n]:""
Can anyone please help us, we'd really appreciate it.
Tcl's [...] is the command substitution syntax just like $(...) in Bash.
And [...] is also special for glob patterns (or regular expressions).
So you should write like this:
/usr/bin/expect -f - << 'QUOTED-EOD'
spawn /usr/bin/profiles -D
expect "Are you sure you want to delete all configuration profiles? \\\[y/n]:"
send "y\n"
expect eof; # This is required!
QUOTED-EOD
Or you can use Tcl's {...} quote style (like Bash's single quotes '...'):
expect {Are you sure you want to delete all configuration profiles? \[y/n]:}; # The `[' still needs to be escaped.
Or just
expect {\[y/n]:}
First of all, you don't need to use expect here. You can just use the following flag:
-f, auto confirm any questions
i.e.
/usr/bin/profiles -fD
since I already typed up the expect explanation:
Square brackets are evaluated as command substitutions and also need to be escaped in regex matches. You can use the {} notation to avoid this.
/usr/bin/expect -f - <<EOD
spawn /usr/bin/profiles -D
expect {Are you sure you want to delete all configuration profiles? \[y/n]:}
send "y\n"
EOD

capture expect ssh output to variable

Hey am new to bash scripts and was wondering how would I capture the output of the ssh command into a bash variable? I looked around and cant seem to get it right. I have tried puts $expect_out(buffer) but when echo it says variable does not exist
I know the response should be just one line and if I want to save that into a variable response and then echo it how would I do that?
A generic idea can be something like as below.
spawn the ssh session
make proper login
Send each commands with send
Wait for desired output with expect
Example:
spawn ssh $user#$domain
expect "password" { send "$pwd\r"}
expect "#"; # This '#' is nothing but the terminal prompt
send "$cmd\r"
expect "#"
puts $expect_out(buffer); #Will print the output of the 'cmd' output now.
The word to wait for after executing the command can vary based on your system. It can be # or $ or > or :; So, make sure you are giving the correct one. Or, you can provide a generalized pattern for the prompt as such
set prompt "#|>|:|\\\$"; # We escaped the `$` symbol with backslash to match literal '$'
While using the expect after sending the commands, it can be used as
expect -re $prompt; #Using regex to match the pattern`

Resources