免交互

133 阅读6分钟

image.png


Here Document 免交互

使用I/O重定向的方式将命令列表提供给交互式程序或命令,如ftp 、cat或read命令

补充:read只接收第一行内容,遇到回车符就会将值赋给变量。 image.png

是标准输入的一种替代品可以帮助脚本开发如人愿不必使用临时文件来构建输入信息,而是直接就地生产出一个“文件”并用作“命令”的标准输入。Here Document 也可以与非交互式程序和命令一起使用。

语法格式

命令 <<标记
...
内容             #标记之际教案是传入的内容
...
标记

补充

  • <:从文件中读取数据,给前面的程序
  • <<:Here Document的重定向方式
  • <<<:从表达式中得到值,给前面的命令

注意事项

  • 标记可以使用任意合法字符(通常为EOF,其他字符也可) image.png

  • 结尾的标记一定要顶格写,前面不能有任何字符

  • 结尾的标记后面也不能有任何字符(包括空格) image.png

  • 开头标记前后的空格会被省略掉 image.png

应用

行数统计

免交互方式实现对行数的统计,将要统计的内容置于标记"EOF"之间,直接将内容传给wc -l来统计。 image.png

修改用户密码

修改密码需要输入两次来确认设置的密码。 image.png

  • 方法一:管道符传递 image.png

  • 方法二:免交互 image.png

将内容导入文件

  • 方法一:echo重定向输出到文件中 image.png

  • 方法二:免交互 image.png image.png

Tee

重新实现重定向输出标准输出两个功能(默认覆盖image.png

也可以结合管道符进行使用 image.png

重定向输出默认覆盖,如果要追加,则需要加-a选项。 image.png image.png

支持变量替换

  • 在写入文件时会先将变量替换成实际值,再结合cat命令完成写入。 image.png

    执行之后会多出所设文件,查看文件内容,里面变量以变为变量i的内容。 image.png

  • 将内容赋给新的变量也可替换里面的变量。 image.png

    换行符未被识别 image.png

    输出字符串加上双引号能识别特殊字符,加上””才会保持原来格式 image.png image.png

关闭变量替换

起始标记字符用单引号括起来的话,里面的$将被视为普通字符,不能转换变量的值。 image.png

再次运行脚本,变量并未被替换。 image.png

或者将$转义,也不会被替换。 image.png image.png

抑制制表符

image.png image.png

起始标记字符前面加 - ,可以抑制每行行首的TAB制表符。 image.png image.png

多行注释

Bash的默认注释是#,该注释方法只支持单行注释,引入Here Document解决多行注释的问题。

“:”代表什么都不做的空命令。中间标记区的内容不会被执行,会被bash忽略掉,因此可达到批量注释效果。

image.png image.png

但由于用#单行注释更显眼,所以依然建议用单行注释。 image.png

expect免交互

建立在tcl语言基础上的一个工具,常被用于进行自动化控制和测试,解决shell脚本中交互相关的问题。

要使用expect免交互,需要安装expect和tcl。 image.png

基本命令

  1. 脚本解释器
    expect 脚本中首先引入文件,表明使用的是哪一个shell。
#!/usr/bin/expect

2. spawn
spawn后面通常跟一个Linux执行命令,表示开启一个会话、启动进程,并跟踪后续交互信息。
例:spawn passwd root

  1. expect

    • 判断上次输出结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回
    • 只能捕捉由spawn启动的进程的输出
    • 用于接收命令执行后的输出,然后和期望的字符串匹配 (模拟用户对包含指定字符串的提示进行操作回应)
  2. send 向进程发送字符串,用于模拟用户的输入。该命令不能自动回车换行,一般要加\r(回车)或\n(换行)

    • 方式一:同一行send部分要有{ }

        expect "密码" {send "123123\r"}
      
    • 方式二:换行send不需要有{ }

        expect "密码"
        send "123123\r"
      
    • 方式三:多个分支,只要匹配了其中一个情况,执行相应的send语句后退出该expect语句

        expect
        {
        "密码1" {send "abcabc\r"}
        "密码2" {send "123123\r"}
        "密码3" {send "123456\r"}
        }
      
  3. 结束符
    两种结束符

    • expect eof:表示交互结束,等待执行结束,退回到原用户,与spawn对应。
      比如切换到root用户,expect脚本默认的是等待10s,当执行完命令后,默认停留10s后,自动切回了原用户。
    • interact:执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端而不会退回到原终端,这个时候就可以手工操作了。
      interact后的命令不起作用,如interact后添加exit,并不会退出root用户。而如果没有interact则登录完成后会退出,而不是留在远程终端上。
      使用interact会保持在终端而不会退回到原终端
      • 如切换到root用户,会一直在root用户状态下
      • 如ssh到另一服务器,会一直在目标服务器终端,不会切换回的原服务器

:expect eof与interact只能选择其中一个使用,不能同时使用

  1. set expect默认的超时时间是10秒,通过 set 命令可以设置会话超时时间。若不限制超时时间则应设置为-1。 例:set timeout 30

  2. exp_continue
    exp_continue附加于某个expect判断项之后,可以使该项被匹配后,还能继续匹配该expect判断语句内的其他项。exp_contite类似于控制语句中的continue语句。表示允许expect继续向下执行指令。
    例如:下例将判断交互输出中是否存在 yes/no 或 *password。如果匹配yes/no则输出 yes 并再次执行判断,如果匹配*password则输出123123并结束该段expect语句。

expect{
    "(yes/no)" {send "tes\r"; exp_continue;}
    "*password" {set timeout 300; send "123123\r";}
}

注意:使用exp_continue时,如果跟踪像passwd这样的输入密码后就结束进程的命令,expect{}外不要再加上expect eof,因为spawn进程结束后会默认向expect发送eof,会导致后面的expect eof执行报错。

  1. send user
    send user表示回显命令,相当于echo

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

    • set hostname [lindex $argv 0]相当于hostname=$1
    • set passwd [lindex $argv 1]相当于passwd=$2

应用

修改用户密码

脚本内容
#!/usr/bin/expect

#使用 spawn 开启跟踪进程
spawn passwd zhangsan

#使用 expect捕捉系统提示信息,判断是否匹配已给定的信息
expect "新的 密码"
#如果expect匹配成功,则发送指定的内容给被跟踪的进程,结尾需要加上\r或\n模拟键入回车
send "123123\r"

expect "重新输入新的 密码" {send "123123\n"}
#使用expect eof结束交互
expect eof
执行结果

image.png

但上述内容是将用户名和密码写入脚本,泛用性极差。通过获取参数,即可改变此情况。

脚本内容
#!/usr/bin/expect
set username [lindex $argv 0]  #第一个位置变量给username
set passwd [lindex $argv 1]  #第二个位置变量给passwd

#使用 spawn 开启跟踪进程
spawn passwd $username

#使用 expect捕捉系统提示信息,判断是否匹配已给定的信息
expect "新的 密码"
#如果expect匹配成功,则发送指定的内容给被跟踪的进程,结尾需要加上\r或\n模拟键入回车
send "$passwd\r"

expect "重新输入新的 密码" {send "$passwd\n"}
#使用expect eof结束交互
expect eof
执行结果

在运行脚本后增加参数,即可适用于其他用户,且能自主设置密码。 image.png

/bin/bash环境下使用expect

如果一定要/bin/bash的环境执行,可通过Here Document免交互导入实现。 QQ图片20220914173425.png

免交互实现su

脚本内容
#!/usr/bin/expect

set username [lindex $argv 0]
set password [lindex $argv 1]

spawn su $username

expect "密码:"
send "$password\r"

expect "*]#"
send_user "切换${username}成功"

interact
解析
  • 切换后匹配对应的用户,并输出提示 image.png image.png

  • 结束符,interact会把控制权交给控制台 image.png

执行结果

image.png

如果结束符换成expect eof,过段时间会退回原用户,而且不会将控制权交给控制台。 image.png image.png

免交互实现ssh

脚本内容
#!/usr/bin/expect

set username [lindex $argv 0]
set hostname [lindex $argv 1]
set password [lindex $argv 2]

spawn ssh ${username}@${hostname}
expect {
        "Connection refused" {send_user "ssh访问被拒绝\n"}
        "No route to host" {send_user "主机名/IP有误\n"}
        "(yes/no)" {send "yes\r";exp_continue}
        "password:" {send "${password}\r"}
}
interact
解析
  • 包含exp_continue项为可选匹配,未被匹配上,就执行后面的匹配。 image.png
执行结果

image.png