シェルスクリプト-expectの包括的な使用(アプリケーションケースを含む)

概要を期待する

  • Expectはtclに基づくツールであり、Expectは自動化された制御とテストのためのツールです。主に、シェルスクリプトの非相互作用の問題を解決します。大規模なLinuxの運用と保守に非常に役立ちます
  • Linuxの運用、保守、開発では、運用のためにサーバーにリモートログインする必要があります。ログインプロセスはインタラクティブなプロセスであり、yes / noパスワードなどの情報を入力する必要がある場合があります。この入力をシミュレートするために、Expectスクリプトを使用できます

期待を使用する前にインストールする必要があります
yum –y intall expect

基本コマンド

  • send:ユーザーの入力をシミュレートするためにプロセスに文字列を送信します。
    このコマンドは自動的に入力して折り返すことはできません。通常、追加する必要があります。\ r(キャリッジリターン)

  • expect:expectの内部コマンド。指定された文字列が最後の出力結果に含まれるかどうかを判別し、含まれる場合はすぐに戻ります。含まれない場合は、タイムアウト期間を待機した後に戻ります。スポーンによって開始されたプロセスの出力のみをキャプチャできます

  • スポーン:プロセスを開始し、後続のインタラクション情報を追跡します

  • 対話:実行が完了した後、対話状態を維持し、制御をコンソールに転送します

  • タイムアウト:タイムアウト期間を指定し、期限が切れても後続の命令を実行し続けます

  • exp_continue:期待を許可する続けるダウン命令を実行する

  • send_user:echoコマンド、echoと同等

  • $ argvパラメーター配列:Expectスクリプトは、bashから渡されたパラメーターを受け入れることができます。これは、[lindex $ argv n]を使用して取得できます。nは0から始まり、それぞれ1番目、2番目、3番目のパラメーターを示します。

期待スクリプトはinteractまたはexpecteofで終了する必要があり、expecteofは通常自動化されたタスクを実行するのに十分です

アプリケーション

ディスク自動パーティションスクリプト

#!/bin/bash

#安装expect
rpm -q expect &>/dev/null
if [ $? -ne 0 ];then
	yum install -y expect >/dev/null
	echo "expect安装成功"
fi

#设置挂载硬盘的参数
fdisk -l |egrep '^Disk /dev/sd.*'
read -p "请输入需要挂载得硬盘路径: " disk_new
partitions="${disk_new}1"

#expect交互脚本
/usr/bin/expect << EOF
set timeout 30
spawn bash -c "fdisk $disk_new"

expect "Command*" {send "n\r"} 
expect "*p*" {send "p\r"}
expect "*1*" {send "\r"}
expect "First*" {send "\r"}
expect "Last*" {send "\r"}
expect "*help*" {send "wq\r"} 

expect eof
interact	
EOF

#格式化磁盘
mkfs -t xfs $partitions


#挂载
read -p "输入需要挂载得路径:" target_dir
if [ ! -d $target_dir ]
then
	mkdir -p $target_dir
fi
echo "$partitions            $target_dir                xfs       defaults              0 0" >> /etc/fstab

#重载fstab配置
mount -a
df -Th

リモートssh別のホスト

要件1:リモートでサーバーにログインし、何もしません

#!/usr/bin/expect
# 开启一个程序
spawn ssh [email protected]
# 捕获相关内容
expect {
    
    
        "(yes/no)?" {
    
     send "yes\r";exp_continue }
        "password:" {
    
     send "123456\r" }
}
interact  # interact 这个写在最后代表交互,如果不写执行完动作就会退出

脚本执行方式:
# ./expect.sh
# /shell/expect.sh
# expect -f expect.sh

1)定义变量
#!/usr/bin/expect
set ip 192.168.188.188
set pass 123
set timeout 5
spawn ssh root@$ip
expect {
    
    
    "yes/no" {
    
     send "yes\r";exp_continue }
    "password:" {
    
     send "$pass\r" }
}
interact


2)使用位置参数
#!/usr/bin/expect
set ip [ lindex $argv 0 ]
set pass [ lindex $argv 1 ]
set timeout 5
spawn ssh root@$ip
expect {
    
    
    "yes/no" {
    
     send "yes\r";exp_continue }
    "password:" {
    
     send "$pass\r" }
}
interact

要件2:リモートでサーバーにログインして操作する

#!/usr/bin/expect
set ip 192.168.188.188
set pass 123
set timeout 5
spawn ssh root@$ip
expect {
    
    
    "yes/no" {
    
     send "yes\r";exp_continue }
    "password:" {
    
     send "$pass\r" }
}

expect "#"
send "rm -rf /tmp/*\r"		# 删除临时文件
send "touch /tmp/file{1..3}\r"	# 创建临时文件
send "date\r"
send "exit\r"
expect eof

要件3:シェルスクリプトを組み合わせて、複数のサーバー上にユーザーを作成することを期待する

[root@server shell04]# cat ip.txt 
192.168.188.188 123
192.168.188.186 123


1. 循环  useradd username
2. 登录远程主机——>ssh——>从ip.txt文件里获取IP和密码分别赋值给两个变量
3. 使用expect程序来解决交互问题


#!/bin/bash
# 循环在指定的服务器上创建用户和文件
while read ip pass
do
    /usr/bin/expect <<-EOF &>/dev/null
    spawn ssh root@$ip
    expect {
    
    
    "yes/no" {
    
     send "yes\r";exp_continue }
    "password:" {
    
     send "$pass\r" }
    }
    expect "#" {
    
     send "useradd maomao;rm -rf /tmp/*;exit\r" }
    expect eof
    EOF
echo "$ip服务器用户创建完毕"
done < ip.txt

自動的にftpに接続してファイルをダウンロードします

#!/bin/bash
#自动连接ftp服务器然后下载pub下面的test.txt
#by stanZ 2021-1-27
if [ $# -eq 0 ];then
        echo "用法:`basename $0` ftp服务器ip地址"
        exit 1
fi
pgrep firewalld &>/dev/null
if [ $? -eq 0 ];then
        systemctl stop firewalld &>/dev/null
fi

if [[ $(getenforce) == Enforcing ]];then
        setenforce 0
        sed -ri '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config &>/dev/null
fi

rpm -q expect &>/dev/null
if [ $? -ne 0 ];then
        [ $UID -eq 0 ] && yum install -y expect &>/dev/null || echo "你没有权限安装expect"
fi

{
    
    
        /usr/bin/expect <<-EOF 
        set timeout 5   
        spawn ftp $1
        expect  {
    
    
                "):" {
    
     send "ftp\r";exp_continue }
                "Password:" {
    
     send "\r" }
        }
        expect "ftp>" 
        send "cd pub\r" 
        send "get test.txt\r" 
        send "bye\r" 
        expect eof
        EOF
}&>/dev/null
wait
echo "test.txt文件下载完毕"
                               

包括的なケース

スプリングボード上のyunweiユーザーの公開鍵を、pingを実行できるLAN内のすべてのマシンにプッシュするスクリプトを記述します。
注:ホストとパスワードのファイルが提供されています

192.168.188.188:123

192.168.188.186:123

ステップ分析

  • 踏み台のyunweiユーザーは、
    アカウントが存在するかどうか判断するためのキーペア(id yunwei)を生成して
    、ユーザーがキーペアファイルを持っているかどうか判断します[-f xxx]
  • 期待プログラムがインストールされているかどうかを確認します
  • LAN内のホストがping可能かどうかを判断します。whileループ本体の
    サイクル判断
    は... pingを実行します。ホストがpingされた場合は、expectプログラムを呼び出し、自動的に応答して公開鍵を押します。
  • パスワードなしのログインが成功するかどうかを確認するためのテスト
  • サーバーのsshサービスポート番号を確認してください
  • 公開鍵をファイルに正常にプッシュしたホストの情報を保存します
  • ファイアウォールとselinuxをオフにします
  • ロギング
  • 公開鍵を押すには、期待する自動応答が必要です

ここでの機能を実現するには、yunweiアカウントに切り替えるための2つのスクリプトファイルを作成する必要があります
。最初のスクリプトはrootによって実行され、
2番目のスクリプトは運用と保守によって実行されます。

#!/bin/bash
#ssh自动上传公钥,并且能远程控制
#by stanZ      2021-1-11
# 判断防火墙是否关闭
pgrep firewalld &>/dev/null
if [ $? -eq 0 ];then
        systemctl stop firewalld &>/dev/null	# 关闭防火墙
fi

# 关闭selinux安全中心
if [[ $(getenforce) = Enforcing ]];then
        setenforce 0
        sed -ri '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config &>/dev/null
fi


{
    
    
id yunwei &>/dev/null	# 判断yunwei账户是否存在 不存在则创建
[ $? -ne 0 ] && useradd yunwei && echo 123|passwd --stdin yunwei
# 给yunwei账户sudo授权 取消注释
sed -ri 's/^#(.*required.*)/\1/' /etc/pam.d/su
sed -ri 's/^#(.*NOPASSWD)/\1/' /etc/sudoers
# 加入wheel组拥有权限
gpasswd -a yunwei wheel
} >/dev/null

# 判断expect是否安装
rpm -q expect &>/dev/null
if [ $? -ne 0 ];then
        yum install -y expect >/dev/null
        echo "expect安装成功"
fi

su - yunwei

補足:

[ ! -f /root/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f /root/.ssh/id_rsa

ssh-keygen -P'' 	设定密码为空

 -f /root/.ssh/id_rsa 指定密钥位置
 
这样就不需要交互操作
#!/bin/bash
#ssh自动上传公钥,并且能远程控制
#by  stanZ     2021-1-11
# 判断私钥是否创建 如果没创建则使用免交互的命令
if [ ! -f /home/yunwei/.ssh/id_rsa ];then
        ssh-keygen -P '' -f ~/.ssh/id_rsa &>/dev/null
fi

while read ip pass
do
{
    
    
        ping -c1 $ip 
        if [ $? -eq 0 ];then
                echo $ip >> /home/yunwei/ip_up.txt
                /usr/bin/expect <<-EOF
                set timeout 10
                spawn ssh-copy-id root@$ip
                expect  "(yes/no)" {
    
     send "yes\r";exp_continue }
                expect  "password:" {
    
     send "$pass\r" }
                        expect eof
                EOF
                else
                        echo $ip >> /home/yunwei/ip_down.txt
                fi
}&>/dev/null
done < /home/ip.txt
wait
echo "公钥推送完毕,准备测试"
remote_ip=`head -1 /home/yunwei/ip_up.txt`
ssh root@$remote_ip hostname &>/dev/null
test $? -eq 0 && echo "公钥成功推送,并且能远程连接"

おすすめ

転載: blog.csdn.net/Cantevenl/article/details/115271301