在 bash 脚本中调用 expect 进行密码检查

在 bash 脚本中调用 expect 进行密码检查

背景:我必须将文件从一台服务器复制到测试环境中的 100 多台服务器。复制文件后,需要更改/验证文件的权限。这些都是 Linux 服务器。大多数服务器的登录密码相同,但有些可能不同。

我需要帮助在我的 bash 脚本中创建一个循环。它实际上是在调用 Expect。我想“改进”或修复的领域有以下几点

  • 需要密码的部分。(* 部分),它应该在 1 次密码尝试失败后退出脚本,并将 IP 转储到名为“fail.txt”的文本文件中
  • 理想情况下,如果没有与服务器的连接,还应该有一个部分将 IP 转储到 fail.txt 中。

我尝试编写密码部分,认为它是一个循环,但我不确定这种思维方式是否可行。我尝试添加另一个“expect Password:”,认为如果再次收到提示,则退出,但我很难让它工作。谢谢!

#!/bin/bash
while read ip; do

sleep 2
expect <<- DONE
        set timeout 1
        spawn scp yoman.txt root@$ip:/felixtemp
                if above command fails, dump the IP to fail.txt, otherwise continue
        expect yes/no { send yes\r }
        expect Password: { send aaaaaa\r } #if this is good, continue the script from *****
                else                                     #exit the script
                expect Password: { send 033\r }
                expect # { send "echo 'password failed'\r" }
                && dump to a text file called fail.txt
*****   expect # { send "exit\r\r" }
        sleep 1

        set timeout 1
        spawn ssh root@$ip
        sleep 2
        expect yes/no { send yes\r }
        sleep 2
        expect Password: { send aaaaaa\r }
        sleep 5
        expect # { send "cd /felixtemp\r" }
        expect # { send "chown informix:informix yoman.txt\r" }
        expect # { send "chmod 775 yoman.txt\r" }
        expect # { send "sum yoman.txt | grep 10350 && echo 'transfer good' || echo 'transfer bad'\r" }
        expect # { send exit\r }
        sleep 1
DONE

done < ip.txt

答案1

如果您必须管理数百台 Linux 服务器,则应使用配置管理工具来执行这些任务。一个非常简单的配置管理工具是 ansible,对管理系统的唯一要求是 python 2.4 或更高版本(http://docs.ansible.com/intro_installation.html#managed-node-requirements)。

您的问题已通过 ansible 解决:

1)定义主机列表,您可以为所有主机定义一个默认密码,并为某些主机定义另一个密码

[hosts_list]
172.17.0.101 ansible_ssh_user=root ansible_ssh_pass=password
172.17.0.102 ansible_ssh_user=root ansible_ssh_pass=oldpassword
172.17.0.103
172.17.0.104

[hosts_list:vars]
ansible_ssh_user=root ansible_ssh_pass=default_password

2)定义一个简单的剧本,其中包含要在托管节点上执行的任务

    root@node1:~# cat play.yoman
---
- hosts: hosts_list
  tasks:
  - name: "Build hosts file"
    copy: src=/root/yoman.txt dest=/tmp/felixtemp owner=user group=adm mode=0755

3)执行剧本并检查结果

root@node1:~# ansible-playbook -i hosts_list play.yoman

PLAY [hosts_list] *************************************************************

GATHERING FACTS ***************************************************************
fatal: [172.17.0.104] => SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue
fatal: [172.17.0.103] => SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue
ok: [172.17.0.101]
fatal: [172.17.0.102] => Authentication failure.

TASK: [Build hosts file] ******************************************************
ok: [172.17.0.101]

PLAY RECAP ********************************************************************
           to retry, use: --limit @/root/play.yoman.retry

172.17.0.101               : ok=2    changed=0    unreachable=0    failed=0
172.17.0.102               : ok=0    changed=0    unreachable=1    failed=0
172.17.0.103               : ok=0    changed=0    unreachable=1    failed=0
172.17.0.104               : ok=0    changed=0    unreachable=1    failed=0

您可以获得已执行任务的服务器列表以及任务失败的服务器列表(原因为无法访问的服务器或密码错误)。您还可以获得文件、其权限和内容未更改的服务器子集,因为它们已更新

答案2

正如 OP 所要求的,先前的评论都没有使用 bash 脚本中的 expect 。

最近,我需要做类似的任务,因此这里是我使用 expect 的解决方案:

expect <<- DONE
    set timeout 1
    spawn scp yoman.txt root@${ip}:/felixtemp
        while 1 {
            expect {
                "no)?"   {
                    send "yes\n"
                }
                "denied" {
                    log_file fail.txt
                    send_log "Couldn't log in to ${ip}.\n";
                    exit 1
                }
                "assword:" {
                    send "${password}\n"
                }
                "100%" {
                     break;
                }

            }
        }
    expect eof
DONE

预期语法的解释:

  • while 1 { }: 形成一个无限循环。在循环内部,我定义了不同的期望情况。
  • log_file fail.txt:创建一个名为fail.txt的文件。
  • send_log“text”:将文本发送到log_file。
  • break:跳出无限循环并结束期望部分。

答案3

你为什么不使用sshpass


环形附有一张表格:

tab=(
     1.2.3.4
     4.3.2.1
     ...
);

for (( i = 1; i < ${#tab[*]}; i++ )) {
        echo ${tab[i]};
        ...
}

您需要针对特定​​ IP 地址的一些条件来设置正确的密码。


SCP

sshpass -p $PASSWORD scp -o StrictHostKeyChecking=no $FILE $USER@$HOST:$PATH

根据手册页,返回值为:

0 成功

1 命令行参数无效

2 给出相互矛盾的论点

3 常见运行时错误

4 无法识别来自 ssh 的响应(解析错误)

5 密码无效/不正确

6 主机公钥未知。sshpass 退出而不确认新密钥。

如果您想在文件中打印 $HOST 并返回以下值,这将很有用:

sshpass -p $PASSWORD scp -o StrictHostKeyChecking=no $FILE $USER@$HOST:$PATH

if [ $? -ne 0 ]
then
    echo $HOST:$? >> file.txt;
fi

SSH

发送命令:

sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no $USER@$HOST $CMD

相关内容