You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用scp的Expect脚本无法完整复制全部文件的问题排查

问题排查与修复方案

首先,咱们先揪出最致命的问题:你脚本里的expect eof { return}这行代码,return会在第一个scp任务完成后直接退出整个脚本!这就是为什么加了set timeout -1后,只能复制第一个文件就停的原因——第一个scp刚结束,脚本就直接返回退出了,后面的循环根本没机会执行。

修复步骤1:移除导致提前退出的return

把这行:

expect eof { return}

改成:

expect eof

或者如果想明确继续循环,可以写expect eof { continue},不过expect eof本身执行完就会自动进入下一次循环,不需要额外的continue。

修复步骤2:重构参数处理逻辑,避免索引错误

你原来手动维护i和y索引的方式很容易出错,比如lindex $argv $i+1在Expect里不会自动计算数值(它会把$i+1当成字符串索引,比如1+1而不是2),这可能导致你的目录/文件列表出现异常(比如你生成的DIRECTORIES里第一个目录重复了两次)。

咱们换成更简洁可靠的两两分组遍历方式,直接把$argv里的元素按「目录、文件」的顺序分组:

set myDirs {}
set myFiles {}
# 自动将argv中的元素两两分组,dir对应目录,file对应文件
foreach {dir file} $argv {
    lappend myDirs $dir
    lappend myFiles $file
}
# 过滤空元素(如果有的话)
set DIRECTORIES [lsearch -all -inline -not -exact $myDirs {}]
set FILES [lsearch -all -inline -not -exact $myFiles {}]

这样就完全避免了手动计算索引的错误,保证目录和文件的对应关系绝对正确。

修复步骤3:处理主机密钥确认(可选但重要)

如果是第一次连接目标主机,scp会弹出Are you sure you want to continue connecting (yes/no)?的提示,你的原脚本没处理这种情况,会导致脚本卡住。咱们把expect的逻辑改成多分支处理:

foreach file $FILES dir $DIRECTORIES {
    puts " Fichier : $file et repertoire : $dir"
    spawn scp -p "$mySource/$file" "$myDest/$dir"
    expect {
        # 处理首次连接的主机密钥确认
        "Are you sure you want to continue connecting (yes/no)?" {
            send "yes\r"
            exp_continue ;# 继续等待密码提示
        }
        # 处理密码输入
        -re "(.*)assword: " {
            sleep 1
            send -- "$mdproot\r"
        }
    }
    expect eof
}

修复步骤4:设置合理的超时时间

在脚本开头添加set timeout -1,让Expect永不超时,避免大文件复制时因为默认10秒超时导致复制中断:

#!/usr/bin/expect -f
set timeout -1 ;# 永不超时,适配大文件复制
set mdproot "****"
set mySource "****"
set myDest "****"

完整修复后的脚本

把这些修改整合起来,最终的脚本应该是这样的:

#!/usr/bin/expect -f
set timeout -1
set mdproot "****"
set mySource "****"
set myDest "****"

set myDirs {}
set myFiles {}
foreach {dir file} $argv {
    lappend myDirs $dir
    lappend myFiles $file
}

set DIRECTORIES [lsearch -all -inline -not -exact $myDirs {}]
set FILES [lsearch -all -inline -not -exact $myFiles {}]

foreach file $FILES dir $DIRECTORIES {
    puts " Fichier : $file et repertoire : $dir"
    spawn scp -p "$mySource/$file" "$myDest/$dir"
    expect {
        "Are you sure you want to continue connecting (yes/no)?" {
            send "yes\r"
            exp_continue
        }
        -re "(.*)assword: " {
            sleep 1
            send -- "$mdproot\r"
        }
    }
    expect eof
}

为什么原来的脚本复制到第4个就停?

原脚本没有设置超时,默认超时是10秒,如果前面的文件复制时间超过10秒,Expect会超时退出;再加上参数处理的索引错误,可能导致后续的目录/文件对应关系混乱,最终脚本提前终止。现在修复后,这些问题都能解决。

内容的提问来源于stack exchange,提问作者lL. Bob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:37:05