从 Bash 调用的 Expect 脚本的退出状态代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1302113/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:25:52  来源:igfitidea点击:

Exit status code for Expect script called from Bash

bashloginsshtclexpect

提问by Sharjeel

I made a Bash script which uses an expect script to automate ssh logins.The script connects to multiple servers and runs some commands. The bash script prompts for login credentials once.

我制作了一个 Bash 脚本,它使用一个 expect 脚本来自动执行 ssh 登录。该脚本连接到多个服务器并运行一些命令。bash 脚本会提示输入登录凭据一次。

I want to incorporate a feature wherein the script terminates if the login fails for the first server to avoid the script checking for next servers resulting in the user account getting locked. The account lockout happens for 3 consecutive login failures and the number of server the script tries to connect is more than 3.

我想加入一个功能,如果第一台服务器登录失败,脚本将终止,以避免脚本检查下一个服务器导致用户帐户被锁定。帐户锁定发生在连续 3 次登录失败并且脚本尝试连接的服务器数量超过 3 个。

This is the snippet in the bash script which calls the expect script.

这是 bash 脚本中调用 expect 脚本的片段。

countu=0
for servername in $(cat $linux_host_list)
do
./script.expect $LUSERNAME $LPASS $servername Linux >> linux_log_file.txt & < /dev/null
let countl=countl+1
done

and here is the expect script (script.expect) snippet

这是expect脚本(script.expect)片段

#!/usr/bin/expect -f
set timeout 30
set username [lindex $argv 0]
set SPASS [lindex $argv 1]
set servername [lindex $argv 2]
set case [lindex $argv 3]
set prompt "(%|#|\$|%\]) $"
switch $case {
    Linux {
        log_user 0
        spawn ssh -o StrictHostKeyChecking=no $username@$servername
        expect  {
            "assword:" {
                send "$SPASS\r"
                expect -re "$prompt"
            }
            expect -re "$prompt"
        }
        send "sudo su -\r"
        expect {
            "assword:" { send "$SPASS\r" }
        }
        expect -re "$prompt"
        log_user 1
        send "opcagt -status ; opctemplate -l ; cat watch.cf 2> /dev/null\r"
        expect -re "$prompt"
        log_user 0
        send "exit\r"
        expect -re "$prompt"
        log_user 1
    }

I tried grabbing the bash command output ($?) assuming that the bash command would return a non zero value if login fails for incorrect password in the expect script but that did not work out. Any suggestions would be much appreciated.

我尝试获取 bash 命令输出 ( $?),假设如果在 expect 脚本中因密码错误而登录失败,则 bash 命令将返回非零值,但没有成功。任何建议将不胜感激。

回答by glenn Hymanman

For error checking in an expect script, there's a decent example at http://systeminetwork.com/article/handle-errors-expect-scripts

对于预期脚本中的错误检查,http://systeminetwork.com/article/handle-errors-expect-scripts 上有一个不错的示例

What you should do is something like this:

你应该做的是这样的:

proc do_exit {msg} {
    puts stderr $msg
    exit 1
}

switch -exact -- $case {
    Linux {
        spawn ssh ...
        expect {
            -re {assword: $} {
                send -- "$SPASS\r"
                exp_continue 
                # remain in this expect block and look for the next matching pattern
            }
            "some message about incorrect password" {
                do_exit "incorrect password"
            }
            timeout {do_exit "timed out waiting for prompt"}
            default {do_exit "something else happened"}
            -re $prompt
        }
        # ... rest of your script
    }
}

I assume you don't need to know about the exit status of the "opcagt ..." series of commands (you just want to see the contents of the watch.cf file. If you do care, you'll need to get the shell to tell you:

我假设您不需要知道“opcagt ...”系列命令的退出状态(您只想查看 watch.cf 文件的内容。如果您确实关心,则需要获取shell告诉你:

send -- "opcagt -status 2>&1 || echo "non-zero return from opcagt: $?"
expect {
    "non-zero return" { handle error and exit? }
    -re $prompt
}
# ... continue

回答by iElectric

You should seriously take a look at Fabric.

你应该认真看看Fabric

回答by Donal Fellows

The section:

这部分:

    expect  {
        "assword:" {
            send "$SPASS\r"
            expect -re "$prompt"
        }
        expect -re "$prompt"
    }

Looks highly suspicious to me. In particular, I really would expect that to cause things to become confused. A more idiomatic way of writing that would be:

在我看来非常可疑。特别是,我真的希望这会导致事情变得混乱。一种更惯用的写作方式是:

    expect  {
        "assword:" {
            send "$SPASS\r"
            exp_continue
        }
        -re "$prompt"
    }

回答by Donal Fellows

I am not much into scripting and all, thus I cannot write the exact steps or script to prove what I got in mind - kindly excuse

我不太喜欢编写脚本,因此我无法编写确切的步骤或脚本来证明我的想法 - 请原谅

Well, I read that bash provides for a thing called as exit status

好吧,我读到 bash 提供了一种称为退出状态的东西

An exit status is a status of 0 for true and 1 or anything else for false

退出状态是 0 表示真,1 或其他任何表示假的状态

You can see this by executing a command and then checking its exit status by typing "echo $?"

您可以通过执行命令然后通过键入“echo $?”检查其退出状态来查看这一点。

What I suggest is when you try to ssh into one server and authentication fails, there shall be an exit status of something other than 0

我的建议是,当您尝试通过 ssh 连接到一台服务器并且身份验证失败时,退出状态应该不是 0

Getting an if-then-else loop here and checking the status for 0 for execution of script and any other value to exit the script totally with a suitable error message

在此处获取 if-then-else 循环并检查 0 的状态以执行脚本和任何其他值以完全退出脚本并显示合适的错误消息

回答by Douglas Leeder

You're running the expect scripts in the background (&), so you can't have the results of the first one before continuing.

您正在后台 ( &) 中运行 expect 脚本,因此在继续之前您无法获得第一个脚本的结果。

The way your expect script is written, it'll get a 30 second timeout at the second password prompt if the first password fails. Instead, you could do an expectalternative, to see if you get another asswordprompt, and exit immediately.

按照您编写的期望脚本的方式,如果第一个密码失败,它将在第二个密码提示处超时 30 秒。相反,你可以做一个expect替代,看看你是否得到另一个assword提示,然后立即退出。

Then change the shell script to not put the expect calls in the background, instead capture the output with $?and test it.

然后将 shell 脚本更改为不将 expect 调用置于后台,而是捕获输出$?并对其进行测试。