bash script which downloads a file with sftp - shell

I need to make a sftp connection with a password and download a file. There is an ip restriction so first of all i should make a ssh connection. I wrote a script but it stucks after connecting with ssh.
Note: i also tried doing it with an expect script but it also didn't work.
#!/usr/local/bin/
ssh test#test1.t.com
lftp sftp://test2:123456#test2.com
get "file.xls"
Edit: You can also see my expect code here.
#!/usr/local/bin/expect -f
expect -c "
spawn ssh test#test1.t.com
expect \"test\#test1\:\~\$\"
spawn sftp test2#test2.com
expect \"*assword:\"
send \"123456\r\"
expect \"sftp\>\"
send \"get file.xls\r\"
expect \"sftp\>\"
exit 1
";

I'm not sure exactly what you're trying to accomplish here. First, I'll address the problems in your expect script. Since your shebang line invokes expect, you don't need to wrap the expect body in a call to expect. That gets rid of all the backslashes. Next, you have 2 spawn calls, which raises questions about you're intent. I'm going to assume that you want to ssh to test1, then grab the file from test2 so the file exists on test1. This assumption changes the 2nd spawn to a plain send command.
#!/usr/local/bin/expect -f
set shell_prompt "test#test1:~$"
set sftp_prompt "sftp>"
spawn ssh test#test1
expect $shell_prompt
send "sftp test2#test2\r"
expect "*assword:"
send "123456\r"
expect $sftp_prompt
send "get file.xls\r"
expect $sftp_prompt
send "exit\r"
expect $shell_prompt
send "exit\r"
expect eof
Now, you can scp the file to your local machine. Let's put those 2 steps into one shell script:
#!/bin/sh
expect <<'EXPECT_SCRIPT'
set shell_prompt "test#test1:~$"
set sftp_prompt "sftp>"
spawn ssh test#test1
expect $shell_prompt
send "sftp test2#test2\r"
expect "*assword:"
send "123456\r"
expect $sftp_prompt
send "get file.xls\r"
expect $sftp_prompt
send "exit\r"
expect $shell_prompt
send "exit\r"
expect eof
EXPECT_SCRIPT
scp test#test1:file.xls .

Related

Why '\n'('\r') does not work in my expect script

I want to input y+enter to reply the question while executing copy tftp:something.
The script will send y, but \n does not work. It will stay (y/n)y and keep there without exiting or doing something else. I have tried \r, and the result was the same. Does anyone know the reason?
#!bin/bash
expect -c "
set timeout -1
spawn telnet x.x.x.x
expect \"username\"
send \"user\n\"
expect \"password\"
send \"pw\n\"
expect \"model\"
send \"copy tftp:something\n\"
expect \"(y/n)\"
send \"y\n\"
expect eof
"
exit 0
I prefer using \r to "hit enter".
Second, your entire bash script is expect, so remove the outer bash layer.
#!/usr/bin/expect -f
set timeout -1
spawn telnet x.x.x.x
expect "username"
send "user\r"
expect "password"
send "pw\r"
expect "model"
send "copy tftp:something\r"
expect "(y/n)"
send "y\r"
expect eof
If you have more logic in the bash part, to avoid quoting hell use a heredoc:
#!/bin/bash
expect <<'END_EXPECT'
set timeout -1
spawn telnet x.x.x.x
expect "username"
send "user\r"
expect "password"
send "pw\r"
expect "model"
send "copy tftp:something\r"
expect "(y/n)"
send "y\r"
expect eof
END_EXPECT
exit 0

Bash scripting with expect. Set parameters to multiple test boards

I'm working on a small project for school. I'm using 15 or so tuners to emulate a Cell network. I'm by no means well versed in scripting yet. I'm an EE who usually googles until I have some frankencode capable of my purposes.
The goal is the set up all the modules quickly so I thought to automate the process with a script. This requires ssh, and so far I have to manually type in the password each time. This morning I set up a basic test with both Expect and sshpass. In either case I can correctly log in, but not give instructions to the remote machine.
I was reading that sshpass has difficulty with sending remote instruction, correct me if I'm wrong.
/usr/bin/expect << EOF
spawn ssh root#<IP>
expect "(yes/no)?" #Are you sure you want to connect nonsense
send "yes\r"
expect "password"
send "$pass\r"
I tried a few things here to get the device to receive instruction
interact
cat /pathto/config.txt
#or
send "cat /pathto/config.txt
#the real goal is to send this instruction
sqlite3 /database.db "update table set param=X"
EOF
You might as well make it an expect script, not a shell script
#!/usr/bin/expect -f
and then pass the IP address to the script as a command line argument
expect myloginscript.exp 128.0.0.1 the_password
In the expect script, you'll grab that IP address from the arguments list
set ip [lindex $argv 0]
set pass [lindex $argv 1]
(Putting the password on the command line is not good security practice. You can research better methods of passing the password to your expect script.)
To use ssh, you'll be asked "are you sure" only the first time to connect, so let's make that conditional. That is done by letting the expect command wait for several patterns:
spawn ssh root#$ip
expect {
"(yes/no)?" {
send "yes\r"
# continue to wait for the password prompt
exp_continue
}
"password" {
send "$pass\r"
}
}
Once that is sent, you should expect to see your shell prompt. The pattern for this is up to your own configuration but it typically ends with a hash and a space.
expect -re {# $}
Now you can automate the rest of the commands:
send "cat /pathto/config.txt\r"
expect -re {# $}
# note the quoting
send "sqlite3 /database.db \"update table set param='X'\"\r"
expect -re {# $}
At this point, you'll want to log off:
send "exit\r"
expect eof
On the other hand, if you set up ssh private key authentication (see ssh-keygen and ssh-copy-id), you can just do this:
ssh root#IP sqlite3 /database.db "update table set param='$X'"
and not have to get into expect at all.

How to automate the process with expect tool?

I want to automate a process with expect :
1.login with a common user in ssh
2.su to root
3.make diretory /home/test
set user xxxx
set host yyyy
set password1 pass1
set password2 pass2
set timeout 60
spawn ssh $user#$host
expect "*assword:*"
send "$password1\r"
spawn su
expect "*assword:*"
send "$password2\r"
send "mkdir /home/test"
close
How to fix the codes to automate my process?
Basically, expect will work with two feasible commands such as send and expect. In this case, if send is used, then it is mandatory to have expect (in most of the cases) afterwards. (while the vice-versa is not required to be mandatory)
This is because without that we will be missing out what is happening in the spawned process as expect will assume that you simply need to send one string value and not expecting anything else from the session, making the script exits and causing the failure.
Apart from the commands being missed, I see one issue with su command. I hope your intention is to create directory with su command execution in the remote host, not in local. So, assuming that, you just have to send the command as su to the server. Your current code will spawn su in the local machine.
#!/usr/bin/expect
set host xxx.xxx.xxx.xxx
set user dinesh
set loginpwd welcome
set adminpwd root
set timeout 60
set prompt "#|>|\\\$"; # We escaped the `$` symbol with backslash to match literal '$'
spawn ssh $user#$host
expect -nocase "password:"
send "$loginpwd\r"
expect -re $prompt
send "su\r"
expect -nocase "password:"
send "$adminpwd\r"
expect -re $prompt
send "mkdir /home/test\r"
expect -re $prompt
send "logout\r"
expect eof
eof will wait for the closure of the ssh session.

Shell script with SFTP and mget finishing before downloads are complete

Here is my script:
#!/usr/bin/expect
spawn /usr/bin/sftp user#place
expect "password:"
send "mysecret\n"
expect "sftp>"
send "mget dir/*.csv\n";
expect "sftp>"
send "quit\n"
It starts to download but after a few seconds, it sends the quit command and exits the program before the downloads are complete.
The only way I've successfully made it stop is to throw in an "interact" command but because I want to run this as a cron job, I don't want to just spawn processes that end up sitting.
Is there a way to accomplish this?
edit:
Someone will ask why I don't have a key setup... this is the only method allowed to me by the vendor.
Adding the line set timeout -1 appears to have fixed this problem
The whole script should look as such:
#!/usr/bin/expect
set timeout -1
spawn /usr/bin/sftp user#place
expect "password:"
send "mysecret\n"
expect "sftp>"
send "mget dir/*.csv\n";
expect "sftp>"
send "quit\n"
Well, if you can use Perl:
use Net::SFTP::Foreign;
my $sftp = Net::SFTP::Foreign->new('user#place', password => 'mysecret');
$sftp->mget("dir/*.csv", '.',
on_error => sub {
warn "unable to copy '$_[1]{filename}':".$sftp->error."\n";
});
You will have to install Net::SFTP::Foreign and IO::Pty (also available as packages in several linux distributions).

Pipe stdin into "expect" script

I am uploading a file via ftp using expect. The file is piped into my bash script.
#!/bin/bash
HOST='example.com'
USER='XXX'
PASSWD='XXX'
expect << EOT
spawn ftp $HOST
expect "Name*:"
send "$USER\r"
expect "Password:"
send "$PASSWD\r"
expect "ftp>"
send "binary\r"
expect "ftp>"
send "prompt\r"
expect "ftp>"
send "put - $1\r" ####
expect "ftp>"
send "bye\r"
expect eof
EOT
On the highlighted line I want ftp to get access to the main script stdin.
Thank you
I believe the key to what you are looking for is Expect's interact command. You'd get a script like this:
#!/usr/bin/env expect
# Set these in the Tcl way, not the bash way
set HOST "example.com"
set USER "XXX"
set PASSWD "YYY"
# You should recognize this bit...
spawn ftp $HOST
expect "Name*:"
send "$USER\r"
expect "Password:"
send "$PASSWD\r"
expect "ftp>"
send "binary\r"
expect "ftp>"
send "prompt\r"
expect "ftp>"
# New stuff starts here
send "put - [lindex $argv 0]\r"
interact {
"ftp>" { return }
}
send "bye\r"
wait
exit
I've rewritten your script so it doesn't use a here document, because that would have interfered with the reading of the content (here-docs are presented as stdinā€¦) and switched it to use a few more idiomatic ways of doing things (idiomatic argument access being the main one).
That said, if I was doing this sort of thing for real, I'd look into using the ftp package from Tcllib as that talks the protocol directly instead of using a possibly-problematic subprocess. (Indeed, if you were going to be doing this on Windows, you'd have to do it that way because of quirks of how Expect and FTP.EXE work on that platform).

Resources