【问题标题】:Enter sudo password while in expect script在期望脚本中输入 sudo 密码
【发布时间】:2019-09-04 21:27:03
【问题描述】:

我在 bash 脚本中有一个期望代码,类似这样

env input1=${INPUT1} input2=${INPUT2} expect << "EOS"
    set timeout -1
    spawn ./another_script.sh
    expect {
        "Input 1" { send -- "$env(input1)\r";exp_continue }
        "Input 2" { send -- "$env(input2)\r";exp_continue }
        eof
    }
EOS

在执行another_script.sh 期间,系统提示我输入 sudo 密码,但由于我还在期待中,所以我无法输入。 我该怎么做才能输入 sudo 密码并让脚本在此之后继续运行? 我不想将密码保存在脚本中,然后将其传递给期望,但我希望能够输入它。

【问题讨论】:

  • 让用户以交互方式进行控制是 Expect interact 工具的用途。
  • 我找不到使用 interact 的良好/有效示例。我尝试了类似"password for" { interact -o "\r" return ; exp_continue } 的方法,但一个问题是我输入的内容是可见的,另一个问题是在我按下 ENTER 后,什么也没有发生,即。该脚本无法继续工作。
  • 如果你想要这里的expect 专家,我可能想要一个tcl 标签。 (expect 是 TCL 语言的扩展,不是 bash 的一部分;因为您的问题与您如何开始期望 bash 无关,而与它启动后的行为方式无关,这不是特别是一个 bash 问题)。

标签: bash tcl expect


【解决方案1】:

来自man sudo:sudoers 策略将凭据缓存 15 分钟,除非在 sudoers(5) 中被覆盖。

这样,在调用期望之前调用sudo -v。它检查凭据,如果它们没有被缓存,它会询问 root 密码。这样你就可以在expect 和之后的sudo 命令之前输入它们,不需要再次询问。

【讨论】:

  • another_script.sh 执行了几个小时,因此缓存的凭据在此期间超时。
  • @adamm 能否将相关命令添加到/etc/sudoers 以供NOPASSWD 访问?
  • 我做不到。
【解决方案2】:

对于您的评论,我认为您在 cron 中有它。在这种情况下,您需要将脚本作为 sudo 运行。你可以在 sudo crontab 中调用它。你可以通过运行sudo crontab -e 来访问它

【讨论】:

  • 在 cron 中运行是您绝对不能与用户交谈的地方,而必须从其他地方获取凭据。在所有选项中,从文件中读取它是更好的选择。或者您可以简单地将脚本放在 root 的 crontab 中,根本不需要凭据……
【解决方案3】:

处理此类事件的标准方法是查看 sudo 密码的提示,提供它,然后继续。但是对于一个长时间运行的脚本,您需要在期望脚本中缓存密码,这样您就不必在几个小时内多次返回给用户。事实上,为了可用性,您可能需要预先询问密码,而不是等到底层系统需要密码。

幸运的是,expect 包括对 stty 的支持,因此添加起来很容易。

env input1=${INPUT1} input2=${INPUT2} expect << "EOS"
    # Prompt for password, cribbed/converted from example on expect(1) manpage
    stty -echo
    send_tty "sudo password: "
    expect_tty -re "(.*)\n"
    send_tty "\n"
    set password $expect_out(1,string)
    stty echo

    # Rest of the script, with clause for sending the password at the right time
    set timeout -1
    spawn ./another_script.sh
    expect {
        "Input 1" { send -- "$env(input1)\r"; exp_continue }
        "Input 2" { send -- "$env(input2)\r"; exp_continue }
        "assword: " { send -- "$password\r"; exp_continue }
        eof
    }
EOS

【讨论】:

  • 感谢您的评论。我试过你的建议,但我收到了这个错误sudo password: send: spawn id exp0 not open while executing "send_user "\n""你提到我可以观察提示,提供它然后继续。我怎样才能做到这一点?我认为这将是原始问题的答案。
  • 这可能是您将期望脚本包装在 bash 脚本中的方式(我刚刚从您那里复制了该脚本)。我还是不明白为什么写脚本的人会这么期待。
  • 这是因为我不想再为期望脚本添加一个文件。我有一个大的 bash 脚本,我期待其中有一些提示(输入 1 和输入 2)。 Expect 似乎是解决方案,所以我只是将期望“嵌入”到 bash 脚本中。
  • @adamm 我想我已经通过将send_userexpect_user 分别更改为send_ttyexpect_tty 来修复它。我认为 stty 不需要更改。
  • 现在可以使用了。这不是我一直在寻找的问题,但它非常有用。
【解决方案4】:

Donal Fellows 的答案是正确的方法,但为了完整起见,这里是您正在尝试的 interact 解决方案。使用的命令是

expect {
    "Input 1" { send -- "$env(input1)\r"; exp_continue }
    "Input 2" { send -- "$env(input2)\r"; exp_continue }
    "password for" { stty -echo
                    interact -u tty_spawn_id -o "\r" return
                    stty echo
                    exp_continue }
    eof
}

您遇到的问题是您正在使用 stdin 上的脚本运行 expect,因此除非您使用 -u tty_spawn_id 让它与 /dev/tty 和用户一起使用,否则交互会有问题。您需要在此 tty 上明确设置 echo on/off,因为 sudo 只会在生成的命令和期望之间的 pty 上执行此操作。

【讨论】:

    猜你喜欢
    • 2018-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 2017-06-20
    • 2019-02-14
    • 2021-07-19
    相关资源
    最近更新 更多