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
Related
I try to unzip a .zip file in remote sever by local script.
code like this:
expect <<EOF
set timeout -1
spawn ssh root#remote "cd /var/www/ && unzip -o my.zip -d ./dest || echo $?"
expect {
"*(yes/no)*" { send "yes\r"; expect "*password*" { send "password\r" } }
"*password*" { send "password\r"}
}
expect eof
EOF
The result code is zero whether it is an error or not.
I want to get the result code and use it in external of EOF.
But I don't know how to do.
Please help thanks in advance.
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"
.....
}
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)?" {.
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;
}
}
I was lurking on this site for quite awhile now because I am doing an SFTP in a expect/SH script. SSH keygen is not an option for us since we don't have access to the remote server so we're looking into using expect to provide password arg for SFTP.
Here is the script I am working on, and everything is working here except I want to capture or log to an output file if my transfer ("mput") completed successfully. Any advice on what code to put after the "mput" since if I add an expect_out(buffer) after, it is failing.
#!/bin/ksh
DIRROOT=/apps/gen/e2k/sys/bpp
COPYDIR=$DIRROOT/SENT
FILEHASH=TEST.SOME.FILE.*
if [ ! -f $COPYDIR/$FILEHASH ]; then
echo "No File"
fi
# New FTP credential from GIC
FTPSERV=**********
FTPUSER=**********
FTPPWD=**********
FTPDIR=/to-scs
/usr/local/bin/expect -f - <<EOFEXPECT1
#exp_internal 1
set timeout -1
set log [open "/dir/dir1/dir2/MIKETEST.txt" w]
spawn sftp -oPort=10022 $FTPUSER#$FTPSERV
expect "password:"
send "$FTPPWD\r";
expect "sftp> "
send "lcd $COPYDIR \r";
expect "sftp> "
send "cd /recipient \r";
expect "sftp> "
send "mput TEST.SOME.FILE.*\r";
put $log $expect_out(buffer)
close $log
expect "sftp> "
send "bye\r";
expect eof
EOFEXPECT1
if [ $? -eq 0 ]
then
echo "success"
else
echo "fail"
fi
You should be using puts instead of put and i wouldn't rely on $expect_out(buffer) for error checking. Rather use a nested expect statement to trap for common sftp scenarios/errors.
set timeout -1
send "mput TEST.SOME.FILE.*\r";
expect {
#Check for progress, note does not work with all versions of SFTP
#If a match is found restart expect loop
-re "\[0-9]*%" {
set percent $expect_out(0,string)
puts $logf "File transfer at $percent, continuing..."
exp_continue
}
#Check for common errors, by no means all of them
-re "Couldn't|(.*)disconnect|(.*)stalled" {
puts $logf "Unable to transfer file"
exit 1
}
#OK continue
"sftp>" {
puts $logf "File transfer completed"
}
}
Finally, i don't recommend using timeout of -1 (never) as this will lead to a stuck process sooner or later. Rather make us of a timeout value and trap for the possibility of a timeout to occur in the expect block.
set timeout 60
expect {
#Process timed out
timeout {
puts $logf "File transfer timed out"
}
}