I need some help on below code. I just need to achieve some simpliest task. bakcup and replace some ssl certificate files. but it doesn't seem to work. what is wrong with below code:
import_esx() {
local username=root
local backuptimestamp=$(date +"%m-%d-%y-%I:%M:%S_%p")
/usr/bin/expect << EOF
set timeout 30
spawn ssh -l $username $Ip_Address
expect {
"(yes/no)?" { send "yes\r"; exp_continue }
"*?assword: " { send "$CommonPassword\r"; exp_continue}
}
send_user "Backing up current certificates\r"
send "mv /etc/vmware/ssl/rui.key /etc/vmware/ssl/rui.key.$backuptimestamp\r"
send "mv /etc/vmware/ssl/rui.crt /etc/vmware/ssl/rui.crt.$backuptimestamp\r"
send "mv /etc/vmware/ssl/castore.pem /etc/vmware/ssl/castore.pem.$backuptimestamp\r"
EOF
}
thanks
Jerry
expect {
"(yes/no)?" { send "yes\r"; exp_continue }
"*?assword: " { send "$CommonPassword\r"; exp_continue}
}
you exp_continue on each branch: You have to expect something else so you can stop looping.
Before each send, you should expect something, typically the shell prompt. Also, after the last mv command, you need to send "exit\r" and then expect eof
Assuming your shell prompt ends with "dollar space", you can put it all together:
set prompt {[$] $}
expect {
"(yes/no)?" { send "yes\r"; exp_continue }
"*?assword: " { send "$CommonPassword\r"; exp_continue}
-re $prompt
}
send_user "Backing up current certificates\r"
send "mv /etc/vmware/ssl/rui.key /etc/vmware/ssl/rui.key.$backuptimestamp\r"
expect -re $prompt
send "mv /etc/vmware/ssl/rui.crt /etc/vmware/ssl/rui.crt.$backuptimestamp\r"
expect -re $prompt
send "mv /etc/vmware/ssl/castore.pem /etc/vmware/ssl/castore.pem.$backuptimestamp\r"
expect -re $prompt
send "exit\r"
expect eof
Related
Im trying to compile a script that establishes an ssh connecting with a remote machine and searches multiple log files for error messages, my current code is the following:
#!/bin/bash
expect <<-EOF > /home/file
set timeout 3
spawn ssh -oPort=port ip zgrep "error" /dir/dir/file.gz.\[54321\]
expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
expect "*password: " { send "password\r" }
expect "*#" { send "exit\r" }
EOF
expect <<-EOF >> /home/file
set timeout 3
spawn ssh -oPort=port ip zgrep "error" /dir/dir/file1.gz.\[54321\]
expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
expect "*password: " { send "password\r" }
expect "*#" { send "exit\r" }
EOF
expect <<-EOF >> /home/file
set timeout 3 ip
spawn ssh -oPort=port ip grep error /dir/dir/file
expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
expect "*password: " { send "password\r" }
expect "*#" { send "exit\r" }
EOF
expect <<-EOF >> /home/file
set timeout 3
spawn ssh -oPort=port ip grep error /dir/dir/file1
expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
expect "*password: " { send "password\r" }
expect "*#" { send "exit\r" }
EOF
Now have you may have noticed i connect to the machine 4 times, which feels so inefficient, i have tried to put all of this log searches into 1 ssh connection, like the following:
expect <<-EOF > /home/file
set timeout 3
spawn ssh -oPort=port ip zgrep "error" /dir/dir/file.gz.\[54321\]
expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
expect "*password: " { send "password\r" }
expect "*#" { send "grep error /dir/dir/file1\r" }
expect "*#" { send "exit\r" }
EOF
but when i try this i get the error
spawn id exp4 not open
while executing
"expect "*#" { send "grep error /dir/dir/file1\r" }"
What is wrong with this code that make it output this error,
All help appreciated
You can use a single command to do all the work required in one expect session:
expect <<-EOF > /home/file
set timeout 3
spawn ssh -oPort=port ip "zgrep error /dir/dir/file.gz.[54321] ; zgrep error /dir/dir/file1.gz.[54321] ; grep error /dir/dir/file ; grep error /dir/dir/file1"
expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
expect "*password: " { send "password\r" }
expect "*#" { send "exit\r" }
EOF
You will need to modify your quotation " marks and escape characters \ so that the remote shell does not to interpret them. There is no need to wrap the string error in quotation marks.
I need to login to a VM and execute some command there. I have gone through all question related to the same topic but did not find any solution with EXPECT. I am using EXPECT as I need to pass the password while using SSH.
I am getting "command not found error" while executing my script but manually, it is working fine.
#!/usr/bin/expect -f
set user [lindex $argv 0]
set to [lindex $argv 1]
set pass [lindex $argv 2]
set command [lindex $argv 3]
puts "$user, $to , $command and $pass ."
# connect via scp
spawn sudo ssh -t -t -v $user#$to << EOF
ls
EOF
#######################
expect {
-re ".*es.*o.*" {
exp_send "yes\r"
exp_continue
}
-re ".*sword.*" {
exp_send $pass\n
}
}
interact
Error received :
spawn sudo ssh -t -t -v username#server_ip << EOF
Invalid command name "ls"
while executing "ls"
(file "./establishSSHConnection.sh" line 10)
It looks like you are trying to send commands to the remote system in a 'here' doc:
spawn sudo ssh -t -t -v $user#$to << EOF
ls
EOF
Instead, you should use 'exp_send' to send the ls command just before 'interact' i.e., remove the 'here' doc:
spawn sudo ssh -t -t -v $user#$to
And put the ls command here at the end:
expect {
-re ".*es.*o.*" {
exp_send "yes\r"
exp_continue
}
-re ".*sword.*" {
exp_send "$pass\r"
}
}
exp_send "ls\r"
interact
EDIT:
Ah, I misunderstood. If you just want to run the command then you'll need to tell the other end to close the connection:
expect {
-re ".*es.*o.*" {
exp_send "yes\r"
exp_continue
}
-re ".*sword.*" {
exp_send "$pass\r"
}
}
exp_send "ls\r"
exp_send "exit\r"
expect {
eof {puts "Connection closed"}
timeout {puts "Connection timed out"}
}
Expect (being built atop Tcl) does not have here documents.
If you want to execute the command remotely and then end the ssh session, do
set command "ls -lrt" ; # for example
spawn sudo ssh -t -t -v $user#$to $command
# ... log in logic
expect eof
I want to add timeouts if there is no privilege on /tmp folder while scp the file and if there is no sudo privilege while executing the sudo command in below script.Could you please suggest
spawn scp -o StrictHostKeyChecking=no \
/tmp/rem_script.sh $env(user_name)#$env(first_db_node_ip):/tmp
expect "password:"
send -- "$env(rem_password)\r"
expect eof
spawn ssh -o StrictHostKeyChecking=no $env(user_name)#$env(first_db_node_ip)
expect "password:"
send -- "$env(rem_password)\r"
expect -ex $
send "PS1=UGLY-PROMPT'# '\r"
expect "UGLY-PROMPT# "
send "sudo chmod 777 /tmp/rem_script.sh\r"
expect {
"password:" {
send -- "$env(rem_password)\r"
exp_continue
}
"UGLY-PROMPT# " {}
}
send "sudo sh /tmp/rem_script.sh $env(asrm_name) $env(com_str)\r"
expect {
"password:" {
send -- "$env(rem_password)\r"
exp_continue
}
-timeout 60 "UGLY-PROMPT# " {}
}
send "exit\r"
expect eof
The following code in the accepted answer does NOT work:
expect -timeout 60 {
"password:" {
send -- "$env(rem_password)\r"
exp_continue
}
timeout { send_user "timed out!" }
"UGLY-PROMPT# " {}
}
Instead we have to put the -timeout N in the expect {} block. See following example:
[STEP 101] $ cat foo.exp
proc expect_prompt {} {
global spawn_id
expect -re {bash-[.0-9]+(#|\$)}
}
spawn bash --norc --noprofile
expect -timeout 2 {
not-found {}
timeout {
send_user ">>> you should never see this.\n"
}
}
expect {
-timeout 2 not-found {}
timeout {
send_user ">>> instead, you would see this.\n"
}
}
expect_prompt
send "exit\r"
expect eof
[STEP 102] $ expect foo.exp
spawn bash --norc --noprofile
bash-4.4$ >>> instead, you would see this.
exit
exit
[STEP 103] $
You need a "timeout" pattern if you want to do something on the timeout rather than just stop waiting for the listed patterns. Something like the following:
send "sudo sh /tmp/rem_script.sh $env(asrm_name) $env(com_str)\r"
expect {
-timeout 60
"password:" {
send -- "$env(rem_password)\r"
exp_continue
}
timeout { send_user "timed out!" }
"UGLY-PROMPT# " {}
}
Or whatever you want to do when waiting for the other patterns times out.
You may also want to add patterns specifically looking for the error messages if you don't have the sudo or other priviledges that you expect to have.
I created script with expect + ssh + bash executed command to automate some process on remote machine.
Problem is that it is not working everytime.
Sometimes it hangs on password:
Sometimes it logins properly but do not execute remote command, just exit after timeout.
Here bash is script:
#!/bin/bash
USER="user"
PASSWORD="password"
MACHINES="host1 host2 host3 host4"
ex() {
expect -c "
log_file ${MACHINE}.log;#
set timeout 8;
spawn ssh $USER#$MACHINE
expect -re \".*ssword: \" {send \"$PASSWORD\n\"}
expect -re \".*host-.* \" { send \"sudo su -\r\"}
expect -re \".*user: \" { send \"$PASSWORD\r\"}
expect -re \".*# \" { send \"/usr/local/bin/REMOTE.COMMAND.sh\r\"}
expect -re \".*# \" { send \"exit\r\"}
expect -re \".*host-.* \" { send \"exit\r\"}
"
}
machines() {
for MACHINE in $MACHINES ; do
ex &
sleep 0.5
done
}
machines
Here is my working solution - if there is something wrong/not efficient comment please:
#!/bin/bash
USER="user"
PASSWORD="password"
MACHINES="host1 host2 host3 host4"
ex() {
expect -c "
log_file ${MACHINE}.log;#
match_max 100000;
set timeout 30;
spawn ssh $USER#$MACHINE
expect {
-re \".*ssword: \" {send \"$PASSWORD\r\"; exp_continue }
-re \".*user#host-.*\" { send \"sudo su -\r\"; exp_continue }
-re \".*ssword.*:.*\" {send \"$PASSWORD\r\"; exp_continue }
-re \".*host-.*# \" { send \"/usr/local/bin/REMOTE.COMMAND.sh\r\"; }
}
expect {
-re \".*host-.*# \" { send \"exit\r\"; }
}
expect {
-re \".*user#host-.*\" { send \"exit\r\"; }
}
"
}
machines() {
for MACHINE in $MACHINES ; do
ex &
sleep 0.5
done
}
machines
I had some similar problem once.
The problem was due to my SSH usage history, and my ~/.ssh/known_hosts data.
You should try add options to your SSH command, so that it always behave the same wether you have already connected the host or not.
For example :
ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no
You might want to use different kind of authentication with option PubkeyAuthentication.
Try this?:
expect -c "
log_file ${MACHINE}.log;#
set timeout 8;
spawn ssh $USER#$MACHINE
expect {
-re \".*ssword: \" {send \"$PASSWORD\n\";exp_continue}
-re \".*host-.* \" { send \"sudo su -\r\";exp_continue}
-re \".*user: \" { send \"$PASSWORD\r\";exp_continue}
-re \".*# \" { send \"/usr/local/bin/REMOTE.COMMAND.sh\r\";exp_continue}
-re \".*# \" { send \"exit\r\"}
-re \".*host-.* \" { send \"exit\r\"}
}
"
Besides, I have never used expect in a background process.
Here is my script
#!/bin/ksh
RemoteFile=`grep "${File}" ${TempLog}` --> the value of the variable is Site Information_2013-07-04-00-01-26.CSV
/usr/bin/expect << EOF
spawn sftp user#server
expect "password:"
send "123fakepassword\n"
expect "sftp>"
send "cd /home/user/pickup_dir\n"
expect "sftp>"
send "lcd /home/user/Scripts/mart/wmt/RAMDISK0\n"
expect "sftp>"
send "get $RemoteFile\n" ---> I'm trying to pass it here so I can download the file.
expect "sftp>"
send "exit\r"
EOF
But no luck!, How can I pass a filename with double quote so the it will execute as (get "Site Information_2013-07-04-00-01-26.CSV\n") I'm placing it in variable cause the filename change on date. Or A'm I doing it wrong? I know not good to hard code the password but we can't use ssh-key to have a passwordless sftp. Thanks!
You just need to send some quotes. Pick one of
send "get '$RemoteFile'\n"
send "get \"$RemoteFile\"\n"
#!/bin/bash
while true
do
/usr/bin/expect <<EOF
set timeout 300
spawn sftp $remoteUser#$remoteIp
expect "yes/no" {
send "yes\r"
expect "*?assword" { send "$remotePass\r" }
} "*?assword" { send "$remotePass\r" }
expect "sftp> " { send "cd $RemoteFolderPath\r" }
expect "sftp> " { send "mget $remoteFileName\r" }
expect "sftp> " { send "quit\r" }
interact
EOF
done
exit