Search code examples
sftpexpect

SFTP file to get and remove files from remote server


I'm trying to write an expect script to pull files from a remote server onto a local folder, and delete them from the remote as they're pulled in. The script I have that doesn't remove them is:

#!/usr/bin/expect

spawn sftp -oHostKeyAlgorithms=+ssh-dss sftp://<username>@<ftp server>
expect "<username>@<ftp server>'s password:"
send "<password>\n"
expect "sftp>"
send "cd <folder>\n"
expect "sftp>"
send "get *"
expect "sftp>"
send "exit\n"
interact

I could add "rm *" after the get command, but sometimes it loses connection to the server while getting the files and the script stops, so I'd like to remove files as I get them.

I tried setting up a for loop like this:

#!/usr/bin/expect

spawn sftp -oHostKeyAlgorithms=+ssh-dss sftp://<username>@<ftp server>
expect "<username>@<ftp server>'s password:"
send "<password>\n"
expect "sftp>"
send "cd <folder>\n"
expect "sftp>"
set filelist [expr { send "ls -1\n" } ]
foreach file $filelist {
   send "get $file\n"
   expect "sftp>"
   send "rm $file\n"
   expect "sftp>"
}
send "exit\n"
interact

But I get:

invalid bareword "send" in expression " send "ls -1\n" "; should be "$send" or "{send}" or "send(...)" or ...

Can anyone tell me what I'm doing wrong in that script, or if there's another way to achieve what I want?


Solution

  • The error message you get comes from the line

    set filelist [expr { send "ls -1\n" } ]
    

    This is because the expr command evaluates arithmetic and logical expressions (as documented at https://www.tcl-lang.org/man/tcl8.6/TclCmd/expr.htm) but send "ls -1\n" is not an expression it understands.

    If you were trying to read a list of files from your local machine you could do this with

    set filelist [exec ls -1]
    

    However what you really want here is to read a list of files through the ssh connection to the remote machine. This is a little more complicated, you need to use expect to loop over the lines you get back until you see the prompt again, something like this (untested):

    send "ls -1\r"
    expect {
        "sftp>" {}
        -re "(.*)\n" {
            lappend filelist $expect_out(1,string)
            exp_continue
        }
    }
    

    For more info see https://www.tcl-lang.org/man/expect5.31/expect.1.html and https://www.tcl-lang.org/man/tcl8.6/TclCmd/contents.htm .