如何通过SSH与Expect脚本实现远程PC目录创建及文件复制?
解决远程目录创建失败与文件复制问题
从你的错误信息和脚本来看,有两个核心问题导致mkdir命令执行失败,进而影响后续的文件复制操作:
1. mkdir无法递归创建父目录
错误提示bash: mkdir /home/marpic/muonic_data/Data_Q2/2018-03-07: Aucun fichier ou dossier de ce type(法语:无此文件或目录),说明目标路径的上层父目录(比如Data_Q2)可能不存在。默认的mkdir命令只能创建最后一级目录,如果路径中的任何上层目录不存在,就会直接报错。
解决方法:给mkdir添加-p参数,它会自动递归创建所有不存在的父目录:
mkdir -p /home/marpic/muonic_data/Data_Q2/2018-03-07
2. Tcl脚本中变量未正确展开
你修改后的脚本里用单引号包裹了ssh命令:
spawn ssh marpic@192.168.110.90 'mkdir $path/$dir'
在Tcl语法中,单引号不会解析内部的变量(比如$path和$dir),这会导致远程主机的bash收到的命令就是mkdir $path/$dir——而bash环境中并没有定义$path变量,最终执行的命令完全不符合预期。
修正脚本的两种可行方式:
方式一:用双引号包裹ssh命令,让Tcl解析变量
把单引号换成双引号,这样Tcl会先将$path和$dir替换为实际值,再把完整命令传给远程主机:
spawn ssh marpic@192.168.110.90 "mkdir -p $path/$dir"
如果你的$myDest变量格式是user@host:/remote/path,可以先提取出远程路径部分,避免硬编码:
# 从$myDest中剥离出远程路径(去掉user@host:前缀) regexp {.*:(.*)} $myDest -> remote_base_path spawn ssh marpic@192.168.110.90 "mkdir -p $remote_base_path/$dir"
方式二:直接写完整路径,避免变量混淆
如果$dir是日期类目录(比如2018-03-07),可以直接写死远程路径前缀,让命令更清晰:
spawn ssh marpic@192.168.110.90 "mkdir -p /home/marpic/muonic_data/Data_Q2/$dir"
完整修正后的脚本示例
foreach file $FILES dir $DIRECTORIES { set timeout -1; puts "\nFichier : $file \n" puts "Repertoire : $dir \n" # 递归创建远程目标目录 spawn ssh marpic@192.168.110.90 "mkdir -p /home/marpic/muonic_data/Data_Q2/$dir" expect -re "(.*)assword: " {sleep 1; send -- "$pass\r" } expect eof # 复制文件到已创建的远程目录 spawn scp -p -r "$mySource/$file" "$myDest/$dir" expect -re "(.*)assword: " {sleep 1; send -- "$pass\r" } expect -timeout 3600 eof }
额外优化建议
- 为了避免每次ssh/scp都输入密码,建议配置SSH密钥登录,这样脚本无需处理密码输入,运行更稳定也更安全。
- 确保
$FILES和$DIRECTORIES两个列表的长度一致,避免循环时出现文件与目录不匹配的情况。
内容的提问来源于stack exchange,提问作者lL. Bob
相关产品推荐
相关产品推荐

