expect vs. bash read - bash

I'm trying to use expect to talk to a bash script, but I'm missing something. My script is:
#!/bin/bash
echo -n "foo? "
read
echo $REPLY
and my expect script is:
#!/usr/bin/expect
spawn ./script.sh
expect "foo? "
send "bar\r\n"
But I never see bar when I run the expect script. What am I missing here?

Dumb me, I needed to add interact to my expect script so that it can finish "interacting" with the script:
#!/usr/bin/expect
spawn ./script.sh
expect "foo? "
send "bar\r\n"
interact
I found the answer here two minutes after asking this question.

I don't familiar well with expect syntax, but you worth try autoexpect:
autoexpect ./script.sh
It will run script.sh and after you'll finish running it an expect script script.exp will be created in current directory.
After than you can edit it if you need to tune something in it.

Related

standard expect works but xargs does not

I am currently trying to improve my script when using snmpwalk and wanted to incorporate using xargs as this would help me gather information from multiple devices at the same time. Taking small steps I created a simple expect file with the following code:
#!/usr/bin/expect -f
set hostname [lindex $argv 0]
spawn snmpwalk $hostname
interact
From there I created a simple bash script to test the functionality of it with the code here:
#!/bin/bash
cfg=$(cat ./ips)
for c in $cfg
do
expect ./EXPECT/01.exp $c
done
Doing this produces the proper information but takes time as it goes through each IP, one at a time.
I then commented the above code out and created the xargs version here:
#!/bin/bash
xargs -I ADDRESS -P4 expect ./EXPECT/01.exp ADDRESS < ./ips
Once I run the bash script, nothing is produced other then the command from the expect file echoing with no other action. I then looked into it and saw that you can add a "-noecho" switch to it but this didn't fix anything.
I then changed the spawn command to exec but the same issue happens and nothing is shown other then an echo of the command.
Would be interested to see what issue could be causing this.
So the answer was rather simple and a bit embarrassing. The expect file needs some type of expect statement before it will run correctly. I simply put in the following expect syntax regardless if it would see this or not and it worked fine:
expect {
"(yes/no)?" {
send "yes\r"
exp_continue
}
}
From here the script worked as expected and it began to run 4 IP's at a time.

Using bash variable with expect

My script look like this , but not getting the password out.
#!/usr/bin/bash
export -p curdir=`basename ${PWD%/*/*/}`
/usr/bin/expect <<EOF
spawn scp -v -i ... <local file> <remote file containing $curdir>
expect -re "Enter passphrase.+:"
send "<password>\n"
exit;
EOF
exit
Something is wrong, as the passsword is evidently not sent. Something wrong with the expect line, the send line, or ???
When this script is executed it is asking for the password.
Thanks for any help.
I made this way too hard. ftp does everything I needed to do. And there are lots of places on the internet that explain how to use it. One can define bash variables as part of a bash script, and the password is simply part of what you define. scp is great of one copy, but ftp as part of a script is really easy.

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: launching scp after sftp

I could really use some help. I'm still pretty new with expect. I need to launch a scp command directly after I run sftp.
I got the first portion of this script working, my main concern is the bottom portion. I really need to launch a command after this command completes. I'd rather be able to spawn another command than, hack something up like piping this with a sleep command and running it after 10 s or something weird.
Any suggestions are greatly appreciated!
spawn sftp user#host
expect "password: "
send "123\r"
expect "$ "
sleep 2
send "cd mydir\r"
expect "$ "
sleep 2
send "get somefile\r"
expect "$ "
sleep 2
send "bye\r"
expect "$ "
sleep 2
spawn scp somefile user2#host2:/home/user2/
sleep 2
So i figured out I can actually get this to launch the subprocess if I use "exec" instead of spawn.. in other words:
exec scp somefile user2#host2:/home/user2/
the only problem? It prompts me for a password! This shouldn't happen, I already have the ssh-keys installed on both systems. (In other words, if I run the scp command from the host I'm running this expect script on, it will run without prompting me for a password). The system I'm trying to scp to, must be recognizing this newly spawned process as a new host, because its not picking up my ssh-key. Any ideas?
BTW, I apologize I haven't actually posted a "working" script, I can't really do that without comprimising the security of this server. I hope that doesn't detract from anyones ability to assist me.
I think the problem lies with me not terminating the initially spawned process. I don't understand expect enough to do it properly. If I try "close" or "eof", it simply kills the entire script, which I don't want to do just yet (because I still need to scp the file to the second host).
Ensure that your SSH private key is loaded into an agent, and that the environment variables pointing to that agent are active in the session where you're calling scp.
[[ $SSH_AUTH_SOCK ]] || { # if no agent already running...
eval "$(ssh-agent -s)" # ...then start one...
ssh-add /path/to/your/ssh/key # ...load your key...
started_ssh_agent=1 # and flag that we started it ourselves
}
# ...put your script here...
[[ $started_ssh_agent ]] && { # if we started the agent ourselves...
eval "$(ssh-agent -s -k)" # ...then clean up nicely when done.
}
As an aside, I'd strongly suggest replacing the code given in the question with something like the following:
lftp -u user,123 -e 'get /mydir/somefile -o localfile' sftp://host </dev/null
lftp scp://user2#host2 -e 'put localfile -o /home/user2/somefile' </dev/null
Each connection handled in one line, and no silliness messing around with expect.

Input to Expect Script

in my test file, I had this line hello$LG. So, if I do
`cat /test`
It will show in my bash shell - hello$LG
But when I try to do this in my expect script,
$> expect test.sh `cat /test`
It gives me this {hello$LG} . I don't know why it is getting {}. Anyone knows how to fix this?
Expect is based upon TCL, you should use square brackets to execute code. When trying to execute a shell command you should use either exec or open or spawn.
I am not sure what the test.sh does, but
expect [exec test.sh 'cat /test']
might just do the trick.
There's more on running other programs from Tcl here:
http://www.tcl.tk/man/tcl/tutorial/Tcl26.html

Resources