while [ $FileLine -le $FileListLines ];
do
# extract each line from FileList
str=$(tail -n+$FileLine ../$FileList | head -n1)
hostpath=$username#$ip:$str
export hostpath ip
expect -c '
spawn bash -c "scp -pr $env(hostpath) $env(ip)"
expect {
"(yes/no)?"{
send "yes\r"
expect "*?assword:*"
send "password\r"
}
"*?assword:*"{
send "password\r"
}
}
'
FileLine=$(( $FileLine + 1 ))
done
The above is a part of a bash script. The scp command in the expect block is not working, that is, files from the remote machine are not getting copied to the local machine.
The same scp command with the path and hostname is working fine when being run from the terminal.
Add expect eof at the end of the expect code otherwise the scp process would be killed right after the password is sent. (Also add a space between the pattern and { in the expect {} block though not sure if that's a problem.)
expect -c '
spawn bash -c "scp -pr $env(hostpath) $env(ip)"
expect {
"(yes/no)?" {
send "yes\r"
expect "*?assword:*"
send "password\r"
}
"*?assword:*" {
send "password\r"
}
}
expect eof
'
UPDATE
Just tried and "(yes/no)?"{ would not work. The space between the pattern and { is required so it should be "(yes/no)?" {.
Related
I have the following expect script within a bash script and I'm unsure as to why the interact command is not working.
expect <<-EOS
#!/usr/bin/expect
set timeout $EXP_TIMEOUT
send_user "\n The timeout being used is $EXP_TIMEOUT \n"
send_user "\nLogging into remote host via SSH:\n"
spawn ssh -q -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${hostname}
expect "*assword*"
send -- "$secret\r"
expect {
"*assword*" {
send \x03
puts "\nIncorrect Password\n"
}
"$prompt" {
send -- "/usr/seos/bin/sesu - $user\r"
expect "*assword*"
send -- "$secret\r"
expect "$prompt"
send -- "id\r"
expect "$prompt"
send -- "hostname -s\r"
interact
}
}
expect eof
EOS
Thank you all for your help!
interact can't let the user enter data via stdin because you are already redirecting stdin for the here document.
Instead, you can save your here document with all expansions to a variable, and then pass that to -c. Here's a simplified example:
script=$(cat << EOF
spawn vi
send "iHello $(hostname)"
interact
EOF
)
expect -c "$script"
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 wrote an expect script to create a user in unix server. It basically connects via SSH to a server using my credential and su to root to do useradd and etc. (I understand there are other methods to accomplish the same but I am restricted with such settings and environment currently.)
set prompt "(%|#|>|\\\$ )"
set prompt [string trim $prompt]
spawn ssh -o StrictHostKeyChecking=no -l $my_user $hostname
expect "?assword: "
send "$my_pass\r"
expect -re $prompt
send "/usr/bin/su - \r"
expect "?assword: "
send "$root_pass\r"
expect -re $prompt
send "/usr/sbin/useradd -d /export/home/$user -m -s /bin/sh $user \r"
expect -re $prompt
send "/usr/bin/passwd $user \r"
expect "?assword:"
send "$new_pass\r"
expect "?assword:"
send "$new_pass\r"
send "exit\r"
expect -re $prompt
send "exit\r"
expect -re $prompt
However if I am stuck at adding a logic to check whether a user already exists in the system. If it were in bash, I would have added grep -c '^USER' /etc/passwd to check for the returned number. But I am unable to capture the return number from expect. There is so much information returned once I added:
send "egrep -c '^$user' /etc/passwd \r"
set output $expect_out(buffer)
Could someone tell me how to parse out all the output? I know it is a very simple task. It is probably a simple if ... then .. else but I am unable to produce anything useful in the past week.
Assuming your shell on the remote host is sh-based, and the remote system is linux:
set cmd [format {getent passwd %s >/dev/null 2>&1; [ "$?" -eq 2 ] && /usr/sbin/useradd -d /export/home/%s -m -s /bin/sh %s} $user $user $user]
send "$cmd\r"
I'm using format (known as sprintf in other languages) to ease quoting.
After spending another few hours studying tcl, this is working now.
I replace this block of code after I enter the root_pass.
send "\r"
expect -re $prompt
expect *;
send "egrep -c '^$user:' /etc/passwd \r"
expect -re $prompt
set output $expect_out(buffer);
set ans [ split $output \n ]
set var [lindex $ans 1]
if { $var >= 1 } {
puts "Found.\r"
send "exit\r"
expect eof
} else {
puts "Not found.\r"
send "/usr/sbin/useradd -d /export/home/$user -m -s /bin/sh $user \r"
.....
}
i want check some files on remote host are exsit with shell script,for my local machine and remote host are not be trusted with each other,so i use expect in my script,here are my code
expect << EOF
spawn ssh $src_user#$src_host "test -f $src_pub || echo CheckFalse "
expect {
"yes/no*" {
send "yes\n"
}
"$src_host's password:" {
send "$src_passwd\n"
}
eof { exit }
}
expect CheckFalse { exit 11 }
EOF
if [ $? -ne 11 ];then
echo "file is exsit!"
else
echo "file is not exsit!"
fi
Use ssh with a command (using -c).
ssh otherhost -c 'ls /path/ filename'
And parse the output as you wish
There are a few issues with your script
Using test will only check if the file doesn't exist, rather use ls which gives output in both conditions and is easier to work with in this case.
You should use exp_continue after sending the authenticity check and the password so the expect loop can continue from where it left of from the previous match.
Add checks for $src_pub and 'No such file' in your expect block to trap for both conditions as shown below:
Try below:
spawn ssh $src_user#$src_host "ls $src_pub"
expect {
"yes/no*" {
send "yes\n"
exp_continue
}
-re "(.*)assword:" {
send -- "$src_passwd\n"
}
$src_pub {
exit 0;
}
-re "(.*) No such" {
exit 1;
}
}
This is a bash script needs to be run on Solaris which takes files from dirlocal, copies to backupdir and sends them via SFTP. The problem is it sends ony 4-5MB of data and then it hangs (somewhere at mput I think) while manually everything works fine. Don't know what to do really...
#!/bin/bash
export LD_LIBRARY_PATH=".:../tool/bin:$LD_LIBRARY_PATH"
dirlocal=</export/home/somedir>
dirlocal_backup=</export/home/somebackupdir>
filename=*
if [ ! -e ${dirlocal}/${filename} ]; then
exit
fi
hostname=<some_ip_address>
username=ftp
password=FTP
remotedir=<somedir>
cd ${dirlocal}
cp * ${dirlocal_backup}
../tool/bin/expect -f - <<EOFEXPECT1
set timeout 10
spawn -nottycopy -nottyinit sftp ${username}#${hostname}
expect {
(yes/no) {send yes\r ; exp_continue }
"*assword" {send ${password}\r ; exp_continue }
}
expect -timeout 10 sftp { }
send "cd ${remotedir}\r";
expect -timeout 10 sftp { }
send "mput ${filename}\r";
expect -timeout -1 sftp {send "bye\r" }
#send "exit\r"
expect eof
EOFEXPECT1
if [ $? -eq 0 ]
then
rm ${filename} > /dev/null 2>&1
else
echo "something"
fi
Since feature requests to mark a comment as an answer remain declined, I copy the above solution here.
Made it work finally. Edited expect statements were the clue. Thanks for help! Regards from Russia! – user2107698