【问题标题】:use expect in shell script在 shell 脚本中使用期望
【发布时间】:2025-12-12 03:45:01
【问题描述】:

我需要传递两个参数来期望,第一个是要执行的命令,第二个是密码。

这是我的期望.sh

#!/usr/bin/expect 产卵 [lrange $argv 0 0] 期待“密码:” 发送 [lindex $argv 1] 相互作用

主脚本:

./expect.sh "ssh root@$SERVER1" $SERVER1_PASS

错误:

无法执行“{ssh root@xxx.xxx.xx.xxx}”:没有这样的文件或目录 在执行时 “产生 [lrange $argv 0 0]” (文件“./expect.sh”第 2 行)

为什么?

【问题讨论】:

    标签: linux shell expect


    【解决方案1】:

    据我所知,spawn 的第一个参数必须是字符串,而不是字符串列表。

    并且尝试将多字命令行作为单个字符串传递会导致问题。我认为你必须在调用 spawn 之前拆分空格,如果一个参数包含空格,那将会中断。也许最好将密码指定为第一个参数,并将命令指定为其余参数。

    所以尝试一下:

    #!/usr/bin/expect
    spawn [lindex $argv 1] [lrange $argv 2 end]
    expect "password:"
    send [lindex $argv 0]
    interact
    

    但即使这样也行不通。

    根据comp.lang.tcl(Google Groups version)上的Re: expect - spawn fails with argument list,我们必须调用eval来拆分列表。

    所以答案应该是:

    #!/usr/bin/expect
    eval spawn [lrange $argv 1 end]
    expect "password:"
    send [lindex $argv 0]
    interact
    

    最后,你需要在密码后发送回车,所以你想要:

    #!/usr/bin/expect
    eval spawn [lrange $argv 1 end]
    expect "password:"
    send [lindex $argv 0]
    send '\r'
    interact
    

    然后切换顺序,调用时不要引用命令:

    ./expect.sh "$SERVER1_PASS" ssh root@$SERVER1
    

    但其他人已经这样做了。我们不需要重新发明*。

    参见例如expect ssh login script

    【讨论】:

    • 但现在提示输入 ssh 密码,expect 似乎没有发送它
    • 但是,有时它会说无法建立主机的真实性。xxxxxx RSA 密钥指纹是 xxxxxx。确定要继续连接(是/否)?
    【解决方案2】:

    就 scp 而言,我发现 shell 脚本非常令人不安。我决定在 crontab 中使用 php 脚本。

    php有一个函数

    $conn = ssh2_connect($scpServer, 22); 
    

    然后调用

    ssh2_auth_password($conn, $scpUser, $scpPassword);
    
    ssh2_scp_send($conn, $scpLocalPath, $scpRemotePath);
    

    ssh2_scp_recv($conn, $scpRemotePath, $scpLocalPath);
    

    你已经完成了。

    当然你需要定义用户、密码等变量

    虽然我建议你创建一个 linux 用户只是为了这个 scp 的目的。

    为了安装ssh2,try

    【讨论】: