Expect脚本实现SFTP拉取远程文件并逐个删除的问题求助
解决Expect脚本逐个拉取并删除远程文件的问题
你的脚本错误原因
你写的set filelist [expr { send "ls -1\n" } ]是完全错误的用法:
expr是Tcl的表达式计算命令,仅用来处理数值或逻辑运算,不能用来执行Expect的send操作,这直接导致了语法报错。- 就算不用
expr,直接send也没法把ls的结果存到变量里,你需要主动捕获sftp返回的输出内容,才能拿到有效的文件列表。
正确的Expect脚本实现
下面是能实现逐个拉取并删除文件的脚本,核心是捕获ls -1的输出并提取文件名:
#!/usr/bin/expect # 替换为你的实际配置信息 set username "<username>" set ftp_server "<ftp server>" set password "<password>" set remote_folder "<folder>" # 可自定义超时时间(单位:秒) set timeout 30 # 启动sftp连接 spawn sftp -oHostKeyAlgorithms=+ssh-dss sftp://$username@$ftp_server expect "$username@$ftp_server's password:" send "$password\n" expect "sftp>" # 切换到远程目标文件夹 send "cd $remote_folder\n" expect "sftp>" # 获取远程文件列表:发送ls命令并捕获输出 send "ls -1\n" expect { -re {(.+)\nsftp>} { set raw_output $expect_out(1,string) } } # 拆分输出为文件名列表,过滤空行 set filelist [split $raw_output "\n"] foreach file $filelist { if {$file eq ""} { continue } # 拉取文件 send "get $file\n" expect { "sftp>" { # 拉取成功则删除远程文件 send "rm $file\n" expect "sftp>" } timeout { puts "拉取文件 $file 超时,跳过删除" expect "sftp>" } } } # 退出sftp会话 send "exit\n" interact
注意事项
- 如果远程文件名包含空格或特殊字符,需要对文件名做转义,把
send "get $file\n"改成send "get \"$file\"\n",删除命令同理。 - 可以根据网络情况调整
timeout的值,避免因网络延迟导致脚本中断。
替代实现方法
如果不想用Expect,也可以试试这两种更简洁的方式:
- rsync + sshpass:利用
rsync的--remove-source-files参数实现拉取后自动删除源文件,配合sshpass自动输入密码(需先安装sshpass):
sshpass -p "<password>" rsync -avz --remove-source-files <username>@<ftp server>:<folder>/* ./本地目标文件夹/
- ssh + scp组合:先通过ssh获取文件列表,再逐个拉取并删除:
# 获取远程文件列表 filelist=$(sshpass -p "<password>" ssh <username>@<ftp server> "ls -1 <folder>") for file in $filelist; do sshpass -p "<password>" scp <username>@<ftp server>:<folder>/$file ./本地目标文件夹/ # 拉取成功才删除远程文件 if [ $? -eq 0 ]; then sshpass -p "<password>" ssh <username>@<ftp server> "rm <folder>/$file" fi done
内容的提问来源于stack exchange,提问作者Andrew Clemens
相关产品推荐
相关产品推荐

