pass username, pwd, server information in expect shell scripting - bash

I want to pass all the remote server names as shell script arguments and then want my script to copy the given file/directory to all remote servers. Below is my code.
#!/bin/bash
/usr/bin/expect <<EOD
#connect via scp
usr=Joe
pwd=Password
file_location=/home/file1.txt
for a in $#
do
spawn scp -r $file_location "$usr#$a:$file_location"
expect -nocase "password: "
send "$pwd\r"
expect eof
EOD
Username and password is same for all the remote servers. So I am hard-coding them for time being but while running the script I see a problem with that..
>./scp1.sh server1 server2
invalid command name "usr=Joe"
while executing
"usr=Joe"
Any help is appreciated. Thanks!

To read command line arguments from expect:
$argc - number items of arguments passed to a script.
$argv - list of the arguments.
$argv0 - name of the script.
This was take from this site
If you want more help with expect then google about tcl because expect is an extension to tcl language

Related

Passing variable to Expect and Spawn

I'm writing a script that will scp a tar file from my local server to a remote host. Since the script generates the file through a pre-requisite process, the name is generated dynamically. My script needs to take the name of the file and pass it to scp for transfer.
#!/usr/bin/expect -f
spawn scp test.$(date +%y%m%d_%H%M).tar user#IP-ADDRESS:/destination/folder
set pass "password"
expect "password: "
send -- "$pass\r"
expect eof
I've tried setting the filename as a variable but keep seeing the same error:
can't read "(date +%y%m%d_%H%M)": no such variable
while executing "spawn scp test.$(date +%y%m%d_%H%M).tar user#IP-ADDRESS:/destination/folder"
$(date +%y%m%d_%H%M) is not a Tcl command. If you use expect, you have to learn Tcl. To get a formatted date in Tcl, use the clock command. Also, interpolation of the result from a command in Tcl is not done by $(....), but by [....]. You can find examples for this construct here.
Decided to go another route since the team was able to provision a new Artifactory repo for this binary and alike. However, to the advice provided here I was able to make a few discoveries which I used to fix my issues:
I also had a password with $ symbol and that also caused a world of issues.
#!/bin/bash
TEST=$(date +%y%m%d_%H%M)
/usr/bin/expect <<eof
set password {pas\$word}
spawn scp "$TEST" user#IP-ADDRESS:/destination/folder
expect "*password:"
send "$pasword\r"
expect eof

How to use telnet in a script?

I need to connect in a system where I have to SSH first then telnet. Then I can start executing some command.
I am struggling about the telnet part. Can you tell me how I can make it please? Is there another alternative than spawn please? Thank you
#!/bin/bash
cat command.sh | sshpass -p 'passowrd' ssh -q -o StrictHostKeyChecking=no root#pc1;
Then my command.sh
#!/bin/bash
spawn telnet pc_modem
expect "login:"
send "root"
expect "Password:"
send "youyou"
cliclient GetMonitoringData;
In this use, the shebang has no effect*. You're passing the contents of the script file to ssh to be executed line by line as if each line were separate commands that will be interpreted by the shell instead of expect.
Try changing command.sh to something like:
# no shebang here
/bin/expect -f - <<<'spawn telnet pc_modem
expect "login:"
send "root"
expect "Password:"
send "youyou"
cliclient GetMonitoringData;'
This sends the expect script as a here string to expect's STDIN. If you use variables in your expect script you may need to change the quoting or escaping depending on whether they are shell or TCL variables and where the substitution needs to take place.
* The shebang is used by the kernel to select the program to interpret the contents of the file when the file has been marked as executable and is run by invoking the file by its name. When a file is run by explicitly naming the interpreter (e.g. sh run_me or ssh user#host run_me_there) the shebang doesn't come in to play.
I find out the answer and works perfectly :
/bin/expect <<<'spawn telnet pc_modem
expect "login:"
send "root\r"
expect "Password: ";
send "youyou\r"
send "yourcommand1\r"
send "yourcommand2\r"
expect eof
'

Run multiple SSH sessions in parallel

I have a script that helps me update the IOS of my Cisco devices when ever I need to. It works fine and I have no issues with the script itself other then the fact that it only does one device at a time.
Is there something that I can research to make the script run asymmetrically so it can do multiple sessions at one time?
The script consists of an expect script which is setup like so:
set timeout 6
set hostname [lindex argv $0]
set password [lindex argv $1]
spawn ssh $hostname
expect "TACACS*:"
send "$password\r"
expect "#"
send "term length 0\r"
< other similar commands >
interact
The main bash script works as follows:
IP=$(cat ./iphosts)
read -p "Please enter your TACACS Password:" password
for i in $IP
do
expect 01.exp $i $password | tee -a bulk.log
done
interact
Both the expect and .sh script have a little bit more to each but those usually post script completion tasks like reporting or additional commands.
Thank you for any information that you can provide on this!
You can use the xargs tool to start a number of processes in parallel. For example:
#!/bin/sh
read -p "Please enter your TACACS Password:" password
xargs -IADDRESS -P4 expect 01.exp ADDRESS $password < ./iphosts
This uses the -P argument to xargs to run up to 4 processes at a time. You could scale up the argument to -P to run more processes in parallel.
But there's a problem here: you're calling interact in your expect script, which suggests that the script is expecting (possibly requires) interactive input from you when it is running. If this is the case, the solution presented here won't work. You would need to rewrite your expect script so that it does not require any user interaction.
You may also want to investigate a tool like Ansible which (a) does this sort of parallel execution by default and (b) has explicit support for configuring a variety of network devices.

Need modification in an ssh script that's written in expect

Am working on a script to ssh into list of servers using expect tool. Getting below error while running it
./script
#!/usr/local/bin/expect -f
while /usr/bin/read hostname
do
spawn ssh user#$hostname
expect "user#$hostname's password"
send "resuidt\n"
expect "user#$hostname"
interact
done < srvlist
Below is my error:
missing operand at _#_
in expression "_#_/usr/bin/read"
(parsing expression "/usr/bin/read")
invoked from within
"while /usr/bin/read hostname"
(file "./script" line 3)
Need help to fix this error.
You are writing an Expect program, which is basically a Tcl program. Your while loop is not Tcl syntax, but looks like a (Posix/Ksh/Bash/Zsh)-shell script.
You have to make up your mind: Write everything in Tcl, or split your application into two files: One (in shell script) as "main program", and a separate expect script, which will be called by the shell script.
As user1934428 indicates you are using bash-type while loop syntax.
Below is one example of how to make an expect script perform the actions you want.
#!/usr/local/bin/expect -f
set file hostname
set user myusername
set passwd mypassword
set f [open $file]
foreach target [split [read $f] "\n"] {
spawn ssh $user#$target
expect {
timeout {send_user "Expect Timeout\n" ; exit}
"password:"
}
send "$passwd\r"
expect {
timeout {send_user "Expect Timeout\n" ; exit}
"$user#$target"
}
interact
}
close $f
I included timeouts in the expect sections because I've found if you do not add these safety mechanisms the expect script can proceed even without the proper responses.
if you want to use shell variables directly into the expect script then you have to pass those variables as $env(shell_variable_name) inside the expect script
example:spawn ssh $env(myusername)#$env(hostname)

How to execute a expect script while connecting to a ssh server

For example, now I have a "root.exp" expect script as following:
spawn ssh user#ip
expect "Password:"
send "password"
Then, the expect command I want to send to this ssh server is stored in another expect script file branch.exp, which for example is as following:
expect ">>"
send "ls"
My question is, how to call this branch.exp in root.exp? For example, something like following in the root.exp:
spawn ssh user#ip
expect "Password:"
send "password"
*call* branch.exp
As Johannes said, you can use the source command. The Expect and TCL mini reference manual says:
source Procedures and variables can be stored in other files and read using the source command. As the file is read, the commands are executed.
Example:
source ~/def.tcl

Resources