Bash脚本自动化需求:跨主机文件传输与远程脚本执行
搞定自动化跨主机脚本执行与文件传输的Expect方案
我来帮你梳理这个完整流程的实现,顺便排查你可能遇到的问题——毕竟用Expect做交互自动化,最容易踩的就是匹配逻辑、权限和路径的坑。
核心流程回顾
先明确你要实现的三步:
- 源主机 → 目标主机:复制脚本、XML文件
- 目标主机:执行脚本生成结果
- 目标主机 → 源主机:拉回结果文件
完整可复用的Expect脚本示例
下面是一个注释详细的脚本,你可以根据自己的实际路径、账号信息修改:
#!/usr/bin/expect -f # -------------------------- 配置参数 -------------------------- set src_files "/home/your/local/scripts/*.sh /home/your/local/configs/*.xml" # 本地要传的文件 set dest_host "192.168.1.100" # 目标主机IP/域名 set dest_user "ubuntu" # 目标主机账号 set dest_pass "your_target_password" # 目标主机密码(用密钥的话可以删掉) set dest_workdir "/tmp/auto_task" # 目标主机工作目录 set exec_script_name "main_script.sh" # 要执行的脚本名 set result_file_path "/tmp/auto_task/result.log" # 脚本生成的结果文件路径 set local_result_save_dir "/home/your/local/results" # 本地保存结果的目录 # ------------------------------------------------------------- # 1. 先在目标主机创建工作目录(避免路径不存在) spawn ssh $dest_user@$dest_host "mkdir -p $dest_workdir" expect { "yes/no" { send "yes\r"; exp_continue } # 第一次连接的主机密钥确认 "password:" { send "$dest_pass\r"; exp_continue } eof } # 2. 从本地复制文件到目标主机 spawn scp $src_files $dest_user@$dest_host:$dest_workdir expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send "$dest_pass\r"; exp_continue } eof } # 3. SSH到目标主机执行脚本(给脚本加执行权限,确保依赖的XML在同一目录) spawn ssh $dest_user@$dest_host "cd $dest_workdir && chmod +x $exec_script_name && ./$exec_script_name" expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send "$dest_pass\r"; exp_continue } # 如果脚本需要sudo权限,添加下面的匹配(根据实际提示修改字符串) "sudo password for $dest_user:" { send "$dest_pass\r"; exp_continue } eof } # 4. 把结果文件拉回本地 spawn scp $dest_user@$dest_host:$result_file_path $local_result_save_dir expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send "$dest_pass\r"; exp_continue } eof } puts "✅ 全流程执行完成!结果文件已保存到:$local_result_save_dir"
你可能遇到的问题排查
1. SSH连接失败/卡住
- 检查目标主机的SSH服务是否开启:
systemctl status sshd(目标主机上执行) - 确认源主机能ping通目标主机,防火墙允许22端口(如果改了SSH端口,要在ssh/scp命令后加
-p 自定义端口) - 第一次连接目标主机时,Expect会遇到"Are you sure you want to continue connecting?"的提示,脚本里已经加了
yes/no的匹配,别漏了这部分
2. 文件复制失败
- 本地源文件路径要正确,且你有读取权限(可以先手动执行
ls $src_files验证) - 目标主机的
$dest_workdir要有写入权限,要是权限不够,就把创建目录的命令改成sudo mkdir -p $dest_workdir,并在Expect里匹配sudo的密码提示 - 复制多个文件时,通配符要能被本地shell解析(如果是远程路径的通配符,要加引号让远程shell处理,但这里是本地文件,没问题)
3. 脚本执行没结果/报错
- 确保脚本依赖的XML文件已经传到目标主机的同一个目录,或者脚本里的XML路径是绝对路径
- 一定要给脚本加执行权限(
chmod +x),脚本里已经写了这一步,但如果手动测试的话别忘 - 如果脚本需要sudo权限,要准确匹配sudo的密码提示字符串(不同系统提示可能不一样,比如Ubuntu是"[sudo] password for xxx:",CentOS是"Password:")
4. 结果文件拉不回来
- 先确认脚本执行后确实生成了结果文件:可以在执行脚本的步骤后加一句
ssh $dest_user@$dest_host "ls -l $result_file_path",看看文件是否存在 - 本地的
$local_result_save_dir要存在且有写入权限,不然会复制失败
优化建议(更安全更可靠)
- 用SSH密钥代替密码:脚本里写密码不安全,还容易因为交互提示变化出问题。步骤是:
- 源主机生成密钥:
ssh-keygen -t rsa(一路回车就行) - 把公钥传到目标主机:
ssh-copy-id $dest_user@$dest_host - 修改Expect脚本,删掉所有匹配"password:"的逻辑,全程无密码交互
- 源主机生成密钥:
- 增加错误处理:每个步骤后检查执行状态,比如:
spawn ssh $dest_user@$dest_host "mkdir -p $dest_workdir" expect eof catch wait result set exit_code [lindex $result 3] if {$exit_code != 0} { puts "❌ 创建目标目录失败,退出码:$exit_code" exit 1 }
内容的提问来源于stack exchange,提问作者sauumum
相关产品推荐
相关产品推荐

