Shell脚本--Here Document与expect 免交互

Here Document

是一个特殊用途的代码块。它在 Linux Shell 中使用 I/O 重定向的方式将命令列表提供给交互式程序或命令,比如 ftp、cat 或 read 命令。Here Document 是标准输入的一种替代品,可以帮助脚本开发人员不必使用临时文件来构建输入信息,而是直接就地生产出一个文件并用作命令的标准输入

特殊字符“<<”在标记和命令之前,这样做的目的是将命令块的输出重定向到程序或命令的 stdin。标记的选择要确保不会出现在其他地方,避免出现混淆;两个标记之间的内容被当做是一个文件并用作“命令”的标准输入。另外 Here Document 也可以与非交互式程序和命令一起使用

基本语法

命令 << 标记

...

...

标记

注意事项
  • 标记可以使用任意合法字符
  • 结尾的标记一定要顶格写,前面不能有任何字符
  • 结尾的标记后面也不能有任何字符(包括空格)
  • 开头标记前后的空格会被省略掉
  • 在第一行标记前‘-’,这个表示要抑制各行首 TAB 的作用
  • 将<<后的标记用单引号引起来会使两个标记之间的特殊字符失去效果被当成普通字符

示例        配置Java环境变量

cat >> /etc/profile << 'EOF'    //给/etc/profile内写入以下三行内容
export JAVA_HOME=/usr/local/java/
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
EOF

变量设定

Here Document 也支持使用变量,如果标记之间有变量被使用,会先替换变量值。如果想要将一些内容写入文件,除了常规的方法外,也可以使用 Here Document。如果写入的内容中包含变量,在写入文件时要先将变量替换成实际值,在结合 cat 命令完成写入

示例

[root@localhost ~]# vim here_var_replace.sh
#!/bin/bash 
doc_file="2019.txt" 
i="company"
cat > $doc_file << HERE 
Take him from home to $i 
HERE
[root@localhost ~]# chmod +x here_var_replace.sh 
[root@localhost ~]# ./here_var_replace.sh 
[root@localhost ~]# cat 2019.txt
Take him from home to company

在上述执行的过程中,标记内变量 i 的值被替换成了“company”,最终结果输出到

$doc_file 内,其值为 2019.txt。

除了变量替换,还可以使用 Here Document 来进行变量的设定。Here Document 不光可以将标记内容传给命令来执行,还可以将整体赋值给一个变量,然后通过 echo 命令将变量值打印出来 

[root@localhost ~]# vim here_var_set.sh
#!/bin/bash  ivar="Great! Beautyful!"
myvar=$(cat <<EOF	//将Here Document 整体赋值给变量
This is Line 1.
That are Sun,Moon and Stars.
$ivar	//输出时会进行变量替换
EOF
)
echo $myvar
[root@localhost ~]# sh here_var_set.sh
This is Line 1. That are Sun,Moon and Stars. Great! Beautyful!

 在上述操作过程中,$ivar 先进行了替换,之后再转向输出,交由 cat 显示出来,其结果放置到$()中,最后得到上述结果

在脚本内批量注释

:<< 标记

注释内容

标记

expect 免交互

expect 概述 

expect 是建立在 tcl 语言基础上的一个工具,它可以让一些需要交互的任务自动化地完成,相当于模拟了用户和命令行的交互操作。expect 是用来进行自动化控制和测试的工具。主要解决 shell 脚本中不可交互的问题。对于大规模的 Linux 运维很有帮助。

在 Linux 运维和开发中,经常需要远程登录服务器进行操作,登录的过程是一个交互的过程,可能会需要输入 yes/no, password 等信息。为了模拟这种输入,可以使用 expect 脚本。

在实际的生产环境中,有一个常用的场景就是批量配置集群无密钥登录。如果集群的机器数量很多,手动一台一台地去每台机器去配置无密钥是非常糟糕的事情。使用 expect 功能,可以远程登录机器,并通过交互方式进行无密钥登录

安装expect

 yum -y install expect

脚本解释器

expect 脚本中首先引入文件,表明使用的是哪一个 shell。

#!/usr/bin/expect

expect/send

expect

  • 判断上次输出结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回
  • 只能捕捉由spawn启动的进程的输出
  • ·用于接收命令执行后的输出,然后和期望的字符串匹配

send

  • 向进程发送字符串,用于模拟用户的输入
  • 该命令不能自动回车换行,一般要加(回车);回车使用\r表示

下述语法结构中$case1 代表检测命令的输出结果,如果输出内容和$case1 一致,通过send 命令模拟用户发送内容到终端

方式一
expect"$case1" {send "$respond1\r"}
方式二
expect "$case1"
send"$response1\r"
方式三
expect 支持多个分支。相当于if判断
expect       
{
"$case1"{send "$response1\r"} 
"$case2" {send"$response2\r"}
"$case3" {send "$response3\r"}
}

spawn 

spawn 后面通常跟一个命令,表示开启一个会话、启动进程,并跟踪后续交互信息

语法结构

spawn Linux执行命令

例如,如果想要跟踪切换用户的交互信息,可以执行以下命令。
spawn su root

 结束符

  • expect eof :等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了
  • interact : 执行完成后保持交互状态, 把控制权交给控制台,这时可以手动输入信息
  • 需要注意的是,expect eof 与 interact 只能二选一

超时时间

expect 默认的超时时间是 10 秒,通过 set 命令可以设置会话超时时间, 若不限制超时时间则应设置为-1。例如执行以下命令即可将超时时间设置为 30 秒

set timeout 30

exp_continue

exp_continue 表示允许 expect 继续向下执行指令

send_user

send_user 表示回显命令,相当于 echo。

接收参数

expect 脚本可以接受从 bash 传递的参数,使用[lindex $argv n]获得。其中 n 从 0 开始, 分别表示第一个,第二个,第三个参数

参数存在 argv 中,$argc 表示参数个数

if {$argc< 1} {
#do something
send_user "usage: $argv0 <param1><param2> ... " exit
}

在上述脚本中$argv0 是脚本名,但[lindex $argv 0]是第一个参数 param1, [lindex

$argv 1]是第二个参数 param2, 以此类推。send_user 用来显示信息到父进程(一般为用户的 shell)的标准输出

expect执行方式

直接执行

需要将默认命令解释器设置为#!/usr/bin/expect

示例

通过 SSH 方式登录远程服务器,需要输入用户名和密码,比较繁琐。如果服务器比较多,手动输入用户名和密码会耗费大量时间,expect 命令可以实现自动登录远程服务器, 并进入交互模式

#!/usr/bin/expect
# expect 将超时时间设置为 60 秒
set timeout 60
# 记录日志文件
log_file test.log
# 开启控制台输出,为0时,控制台不输出
log_user 1
spawn ssh root@192.168.78.129 -p 22
expect {  
    "(yes/no)?" {      //匹配(yes/no)?
        send "yes\r"      //代替用户输入yes    \r表示回车
        exp_continue      //代码继续向下执行
    }  
    "*password:*" {      //匹配*password:* 
        send "root\r"     //代替用户输入密码
    }  
}
expect {
    "*# " { send "ls -l\r" }    //匹配以#号结尾的行,代替用户输入ls -l命令
    "*\$ " { send "ls -l\r" }
}
expect {
    "*# " { send "exit\r" }    //匹配以#号结尾的行,代替用户输入exit命令
    "*\$ " { send "exit\r" }
}
expect eof

嵌入执行

将expect嵌入到Shell脚本进行执行

在脚本中使用

expect << 标记

expect命令

标记

可以在脚本内嵌套expect

示例

通过 SSH 方式登录远程服务器,需要输入用户名和密码,比较繁琐。如果服务器比较多,手动输入用户名和密码会耗费大量时间,expect 命令可以实现自动登录远程服务器, 并进入交互模式

#!/bin/bash

main()
 {
    if [ $# -ge 5 ];then
    check-ip-survival $1
        if [ $? -eq 0 ];then    
            ssh-connection $@    
        fi
    else
        echo "请输入合适的参数:IP地址 用户名 密码 端口 需要执行的命令"
    fi
}


check-ip-survival() {
    local IP=$1
    echo "正在检查IP地址$1..."
    if [[ $IP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]];then
#awk
                local IPs=$(echo "$IP" | tr '.' ' ' )
                local IP1=$(echo "$IPs" | awk '{print $1}')
                local IP2=$(echo "$IPs" | awk '{print $2}')
                local IP3=$(echo "$IPs" | awk '{print $3}')
                local IP4=$(echo "$IPs" | awk '{print $4}')
                if [ $IP1 -gt 0 ] && [ $IP1 -le 254 ] && [ $IP2 -le 254 ] && [ $IP3 -le 254 ] && [ $IP4 -le 254 ];
                then
                        echo -e "IP地址$IP正在连接..."
                else
                        echo -e "IP地址$IP不合法"
            exit 1
                fi
    else    
        echo "IP地址${IP}不合法"
        exit 1
    fi
}
ssh-connection() {
    local IP=$1
    local name=$2
    local password=$3
    local prot=$4
    for ((i=5;i<=$#;i++))     //循环获取到用户输入的命令拼接到一起
    do
            local single=$(echo "$@" | cut -d ' ' -f$i )
            local commend+=$(echo " ${single}")
    done 
    expect << EOF        //嵌入执行expect
        # expect 将超时时间设置为 60 秒
        set timeout 60
        # 记录日志文件
        log_file test.log
        # 开启控制台输出,为0时,控制台不输出
        log_user 1
        spawn ssh ${name}@${IP} -p ${prot}
         expect {  
                    "(yes/no)?" {  
                        send "yes\r"  
                        exp_continue  
                    }  
                    "*password:*" {  
                        send "${password}\r"  
                    }  
        }
         expect {
                        "*# " { send "${cmd}\r" }
                        "*\$ " { send "${cmd}\r" }
                }
                expect {
                        "*# " { send "exit\r" }
                        "*\$ " { send "exit\r" }
                }
        expect eof
EOF
}
main $@
exit
  • 28
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值