【问题标题】:Expect - Direct output of remote command to local fileExpect - 将远程命令直接输出到本地文件
【发布时间】:2018-01-10 08:11:39
【问题描述】:

我正在尝试通过以下方式从 bash 调用期望脚本:

#!/bin/bash

mkfifo foobar
expectScript > foobar &
# other stuff that does stuff with foobar

expectScript 需要做的是 ssh 到远程主机。从那里它需要 ssh 到另一个远程主机。然后需要将用户切换到root(不允许root登录)。然后它需要发出一个最终需要写入 foobar 的命令(例如 tail -f /var/log/messages)。没有其他东西可以写入 foobar,例如密码提示或命令提示。只有命令的输出可以写入 foobar。我的脚本的登录部分工作正常。我正在努力解决的是如何将输出写入 foobar,并以 SIGINT 将终止命令的方式。

这是我所拥有的:

#!/usr/bin/expect --

set HOST1_USER myuser
set HOST2_USER myotheruser
set HOST1_PASSWORD mypassword
set HOST2_PASSWORD myotherpassword
set ROOT_PASSWORD anotherpassword
set HOST1 192.168.0.5
# HOST2 is only reachable from HOST1
set HOST2 192.168.1.12

global until_interrupt
set until_interrupt 0

set HOST1_PROMPT "CL-\\d.*#"
set HOST2_PROMPT "\\\$ $"
set ROOT_PROMPT "# $"

log_user 0

spawn ssh $HOST1_USER@$HOST1
#   ssh keys are exchanged with HOST1, so there is no need for password here
    expect -re "$HOST1_PROMPT" {
            send "ssh HOST2_USER@$HOST2\n"
            expect {
                    -re ".*ssword.*" { send "$HOST2_PASSWORD\n" }
                    -re ".*Are you sure you want to continue connecting.*" {send "yes\n"; exp_continue}
            }
    }

    expect -re "$HOST2_PROMPT" { send "su\n" }
    expect -re ".*ssword.*" { send "ROOT_PASSWORD\n" }

    log_user 1
    # nothing up to this point should have been sent to stdout
    # now I want the output of the tail command to be sent to stdout

    expect -re "$ROOT_PROMPT" { send "tail -f /var/log/messages\n" }

    # I want to wait here until SIGINT is sent.  There may be a better way than the traps below.
    # Set a trap to watch for SIGINT
    trap {
            set until_interrupt sigint_detected
    } SIGINT

    while { $until_interrupt == 0 } {
            #wait until sigint
    }

    send "\003"
    # I think that is SIGINT, and that I'm sending it because I caught the first one in the trap.

    trap {
            exit
    } SIGINT

    set timeout 30

    expect -re "$ROOT_PROMPT" { send "exit\n" }
    expect -re "$HOST2_PROMPT" { send "exit\n" }
    expect -re "$HOST1_PROMPT" { send "exit\n" }
    # Fully exited

【问题讨论】:

  • 大部分expect 脚本可以通过使用公钥身份验证和ssh 内置的隧道支持来消除。
  • 感谢 chepner,但没有什么可以消除的,因为在 HOST2 上我需要以 root 身份运行命令(sudo 不起作用),而 HOST2 不允许 root 通过 ssh 登录。所以需要先用非root用户登录,然后su到root。我已经在公钥认证工作的主机上实现了这个解决方案,而且要容易得多。但是对于这个特定的服务器,我看不出它是如何工作的。
  • 如果你有root密码,你可以配置 sudo工作。没有什么可以阻止您在本地 ssh 配置文件中设置正确的用户 ID 和主机名。
  • 谢谢chepner。我正在登录一个无法对 sudo 进行此类修改的系统,即使我有 root 密码。
  • 还有一个警告让我无法完全避免期望,否则我肯定会走你建议的路线。即使在我以 root 身份登录后,我还需要运行另一个无法组合为 command1 的命令;命令2。 (command1 是 vrctl,因此为 command2 设置上下文。)

标签: linux bash stdout expect fifo


【解决方案1】:

您应该能够使用expect 来回显您发送到遥控器的控制字符(或您的tail -f 命令未生成的其他字符串)。例如这个简单的ssh 示例适用于我(-d 用于调试):

#!/usr/bin/expect -d
log_user 0
spawn ssh localhost
expect " $ "
send "tail -f /var/log/messages\n"
log_user 1
trap {  send "\003" } SIGINT
set timeout -1
expect "\003"
expect "$ "
send "date\r"
expect "$ "

如果我运行这个,将标准输入重定向到 null,我可以在 shell 的背景下键入 Ctrl-C 并且它干净地结束。

./prog </dev/null >/tmp/out &

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 2018-05-16
    相关资源
    最近更新 更多