Automating pear install with expect - bash

I'm working on a small script to try and automate the installation of pear on a system should it be missing - basically, taking the interactive portions of the installation process and making them non-interactive so all I need to do is execute the script and it does it for me on its own. This is my first time trying to use expect and it's, well, not what I expected.
Sample code below:
/usr/bin/expect <<EOD
set timeout 20
set number [lindex $argv 0]
set path [lindex $argv 1]
spawn php -q go-pear.phar
expect "1-11, 'all' or Enter to continue:"
send "$number\r"
interact
expect "Installation base ($prefix) [/usr/local] :"
send "$path\r"
interact
EOD
This is not quite working at the moment as it's trying to fill in the /usr/local portion in the first menu as follows:
1-11, 'all' or Enter to continue: invalid command name "/usr/local"
while executing
"/usr/local"
invoked from within
"expect "Installation base () [/usr/local] :""
Can anyone show me what I'm missing here? Also, I'd like to get this so I don't have to run it as ./script $var0 $var1 but rather just run it as ./script with everything being contained within and filled in, but not sure how to do that.
Thanks in advance for any help you can offer.

One problem is that the [...] inside the string tells expect to execute a command. I think you need to escape them with \[...\].
Hope this helps a little =)

I ended up figuring this out. In case anyone else wants to do something similar, here's what worked for me:
/usr/bin/expect <<EOF
set send_slow {1 .1}
set timeout -1
spawn php -q go-pear.phar
expect "1-11, 'all' or Enter to continue:"
sleep .1
send -s -- "1\r"
expect -exact "1\r"
sleep .1
send -s -- "/usr/local\r"
expect -exact "/usr/local\r"
expect "1-11, 'all' or Enter to continue:"
sleep .1
send -s -- "\r"
expect -exact "\r"
expect EOF

Related

How to spawn telnet session based on user input

I created a script that queried everything on a specified device, however too much data is printed and I'd like to be able to query specific areas of the device configuration depending what arguments are passed.
My initial script which prints everything works fine
#!/usr/bin/expect
set hostName [lindex $argv 0]
set timeout 2
spawn telnet $hostName
expect -re "login"
send "xxx\n"
expect -re "Password:"
send "<password>"
sleep 0.5
send "<query 1>"
sleep 0.5
send "<query 2>"
interact
Now I am creating a help section which involves including bash, and am having some trouble getting both expect & bash to work at the same time, along with being able to interact at the end. Does anyone have any advice?
with the below, the help function works but the send commands etc. don't work
#!/bin/bash
#!/usr/bin/expect -f
With the below I am unable to run the help menu
#!/usr/bin/expect -f
#!/bin/bash
I get this error:
invalid command name "Help()"
while executing
"Help()"
(file "./xxx" line 5)
Does anyone have any advice?

"Expect" command line script to connect to VPN and enter password

I am trying to write an "Expect" script to connect to a VPN...
Trying to write and expect (https://likegeeks.com/expect-command/) script to connect to a vpn, is this the right idea:
The commands to connect are:
sudo vpnName [ENTER] *Password* [ENTER] Random number 1-100 [ENTER] [ENTER]
So the expect script would be something like:
#!/usr/bin/expect -f
set randNum [(( ( RANDOM % 100 ) + 1 ))]
send -- "sudo vpnName\r"
send -- "*password*\r"
send -- "randNum\r \r"
You are trying to combine a bash expression with tcl (language expect is using)
Use instead:
set randNum [expr {int(rand()*100) + 1}]
In expect, you need to spawn a process before you can interact with it:
#!/usr/bin/expect -f
set randNum [expr {int(rand()*100) + 1}] # as per #Sorin's answer
spawn sudo vpnName
expect "assword" # wait for the password prompt
send -- "*password*\r"
expect "whatever matches the random number prompt"
send -- "$randNum\r\r"
# this keeps the vpn process running, but returns interactive control to you:
interact
A tip: while debugging expect code, launch it with expect -d -f file.exp -- this is very valuable to let to see if your expect patterns are matching as you think they should.

why expect shell script for 'obexctl' not working as Expected

I want to send a file using bluetooth from one device to another device. For that i am using obex which has a command called 'obexctl'. It works as
described in this ... Please Take a look into this Doc
This is how sending file works. For automating this process i have written one shell script using expect. which is as below.
#!/usr/bin/expect -f
set address [lindex $argv 0]
set prompt "#"
spawn obexctl
sleep 2
expect -re $prompt
send "connect $address\r"
sleep 5
send "quit\r"
but it didnt work. It doesnt fully execute that connect command.and exit the code. Please let me know if any of you know the solution.

Why does this expect code not work?

Not sure if this is more of a scripting/unix question or a programming one, but I tried on the unix stackexchange and got no responses, so:
The following expect code seems to work; that is, it appears to enter text in answer to the password prompt. However, the device never actually mounts.
But if I simply enter the command into a shell and type the password in by hand the device mounts successfully.
So I'm curious where the input is actually ending up, as it never seems to 'catch' the password yet doesn't present an error message either? In fact the output looks exactly the same in both instances, but only in the case of running the command and typing the password manually do I see my files appear over the network.
Here is the code:
#!/usr/bin/expect
spawn sudo mount.cifs "//WinPC/My Pictures" /home/LinPC/Desktop/Pictures -o user=Me
expect "Password: " {
set send_slow {1 .1}
send -s "a_password"
}
UPDATE: Got the help I needed to make it work: had to insert 'expect eof' after sending the password so that it doesn't end prematurely. However I now wish to progress to changing it to 'expect_background' so that I can have the same trigger response to issuing multiple mount commands. The following ends prematurely, and 'expect eof' at the end causes an error:
expect_background "Password:" {
send "a_password\r"
expect eof
}
spawn sudo mount.cifs "//WinPC/My Pictures" /home/LinPC/Desktop/Pictures -o user=Me
expect eof
What should it look like?
UPDATE: the following code block illustrates the current problem:
expect_background "Password: " {
send "a_password\r"
expect eof
}
spawn sudo mount.cifs "//WinPC/My Pictures" /home/LinPC/Desktop/Pictures -o user=someone
expect "Password: " {
send "a_password\r"
expect eof
}
#The password prompt gets answered by 'expect' but not 'expect_background'.
#If I delete the last 'expect' and insert 'expect eof' it hangs for a short
#while at the password prompt (around 3 seconds) then exits.
#Why?
Add one more expect statement after sending the password.
send -s "a_password\r"
expect eof
The eof will make the Expect to wait till the end of program.

How to use error codes inside bash script

Apologies if this has been asked before, I was unable to find an answer...
I have created a bash script for OS X to mount an AFP share. The script works successfully and allows a user to type their username and password into a graphical popup using cocoa dialog
My issue is that if the username and password are entered incorrectly, I want to be able to display a new pop up window explaining this.
I was trying to do this based on the exit status of the script but the script returns 0 regardless of whether or not the mount was successful
The script is as follows;
cd=/etc/cocoaDialog.app/Contents/MacOS/cocoaDialog
rvUsername=($($cd standard-inputbox --title "Network Mount" --informative-text "Please enter your username"))
username=${rvUsername[1]}
rvPassword=($($cd secure-standard-inputbox --title "Network Mount" --informative-text "Please enter your password"))
password=${rvPassword[1]}
mkdir "/Volumes/Test"
expect <<- DONE
set timeout -1
spawn /sbin/mount_afp -i "afp://servername/Software" /Volumes/Test
expect "*?ser:*"
send "$username\n"
expect "*?assword:*"
send "$password\r"
expect EOF
DONE
If I run this via Terminal or Textmate, I receive the following (as an example)
spawn /sbin/mount_afp -i afp://server/Software /Volumes/Test
User: username
Password:
mount_afp: the volume is already mounted
Program exited with code #0 after 7.32 seconds.
So mount_afp is giving me a message, which I would then like to use in my script...but the exit code is 0 and I don't know how else to get hold of that message to use
Any ideas? (Hope that makes sense!)
To get the exit code of the spawned command, use something like this:
# wait for the command to end : wait for the prompt $ followed by space
expect "\\$ "
send "echo \$?\r"
expect -re "(\\d+)" {
set result $expect_out(1,string)
}
send_user "command exit with result code : $result"
This will take the content of the variable $? (which is the exit code of the prevously ended command) and save it to $result.
Thanks for the responses all, helped point me in the right direction
I ended up taking this approach and setting the expect command as a variable
output=$(su -l $loggedInUser -c expect <<- DONE
set timeout -1
spawn /sbin/mount_afp -i "afp://$serverName" /Volumes/mount
expect "*?ser:*"
send "$username\n"
expect "*?assword:*"
send "$password\r"
expect EOF
DONE)

Resources