【问题标题】:expect script with optional ssh-agent passphrase prompt?期望带有可选 ssh-agent 密码提示的脚本?
【发布时间】:2016-03-04 13:25:06
【问题描述】:

我想在expect 的帮助下自动进行数据库备份:首先,脚本使用ssh 建立从远程数据库端口到我的本地计算机的转发端口。然后我使用数据库实用程序转储所有数据库。

因此,我在 bash 脚本中有以下 expect 脚本:

#!/bin/sh

expect <<- DONE
  set timeout -1

  # port-forward remote database port 3306 to local port 3307
  spawn ssh -M -S /var/run/examplecom-mysql-socket -fnNT -L 3307:localhost:3306 someuser@example.com

  expect {
    # conditional prompt appears in case ssh-agent is not active
    "*.ssh/id_rsa':*" {
      send -- "$SSH_PASSPHRASE\r"
    }
    # ?!?!?!? What to expect here in case ssh-agent is active, therefore no password needed, and therefore no prompt appears?
  }

  # dump remote database by connecting to forwarded port
  spawn mysqldump --all-databases --user=root --password --protocol=TCP --host=localhost --port=3307 --verbose --result-file=${DB_DUMP_FILE}

  expect {
    # prompt appears for database password 
    "*?asswor?:*" {
    send -- "$PASSWORD_MYSQL_ROOT\r"      
    }
  }

  expect eof
DONE

此脚本可能在两种情况下运行:

  • ssh-agent 中的任何一个当前未激活。在这种情况下,生成的 ssh 进程将提示 Enter passphrase for key '${HOME}/.ssh/id_rsa':,第一个 expect 规则很匹配,并正确发送 SSH 密码。
  • ssh-agent 当前处于活动状态。在这种情况下,生成的 ssh 进程会静默建立端口转发,不需要或提示输入 SSH 密码。

我正在努力让这两种情况都在我的期望脚本中工作。特别是,我不知道如何修改脚本以使“静默”的 active-ssh-agent 成为“预期”,因此预期脚本可以继续启动数据库转储。

我尝试了 expect multiple things 方法(在上面的?!?!?!? 评论位置):

  • 期待换行,
  • 期待我的 shell 提示,
  • 期待eof

但没有一个有效。我在 StackExchange 周围发现了类似的问题和建议的解决方案: * How to use expect with optional prompts? * https://superuser.com/q/412259/137881 * TCL / Expect Scripting - Using a conditional statement to attempt a secondary login password

但这些解决方案似乎会导致代码重复:每个条件提示都意味着复制和粘贴脚本的其余部分,这使得脚本很快就会与每个 ssh 语句的嵌套条件提示变得复杂。

ssh 由于活动的 ssh 代理而没有提示输入密码短语/密码的情况下,如何期望正常工作?

【问题讨论】:

    标签: ssh expect ssh-agent


    【解决方案1】:

    是的,这很有趣。由于您使用的是 ssh -N,因此您不会在远程主机上启动任何进程,而 ssh 会话就在那里。你只需要睡几秒钟,然后希望隧道能建立起来。

    set timeout 2
    spawn ssh -M -S /var/run/examplecom-mysql-socket -fnNT -L 3307:localhost:3306 someuser@example.com
    
    expect {
        # conditional prompt appears in case ssh-agent is not active
        "*.ssh/id_rsa':*" { send -- "$SSH_PASSPHRASE\r" }
        # wait until the timeout, then carry on with the rest of the script
        timeout
    }
    
    set timeout -1
    # ...
    

    或者,删除-N,然后您可以期望在远程主机上看到提示。

    spawn ssh -M -S /var/run/examplecom-mysql-socket -fnT -L 3307:localhost:3306 someuser@example.com
    # ..........................................^^^^
    
    expect {
        # conditional prompt appears in case ssh-agent is not active
        "*.ssh/id_rsa':*" { send -- "$SSH_PASSPHRASE\r" }
        # I assume your prompt ends with a dollar sign and a space
        -re {\$ $}
    }
    

    现在您可以生成 mysql 命令并与之交互。

    【讨论】:

    • 太棒了!您的timeout 建议成功了。 2016-03-04 的答案版本依赖于端口转发肯定会在超时之前建立的假设。为了不依赖这个假设,我使用timeout { if {[file exists /var/run/examplecom-mysql-socket]} { send_user "file exists... continuing\r" } else { send_user "file does not exist. This implies ssh port could not be established. Quitting script\r" exit 2 } 对其进行了扩展,从而在未建立套接字(文件)/var/run/examplecom-mysql-socket 的情况下退出。
    猜你喜欢
    • 2013-08-25
    • 2018-02-21
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 2015-11-28
    • 2015-05-13
    相关资源
    最近更新 更多