1、Here Document免交互
1.1 Here Document概述
Here Document是一个特殊用途的代码块,它是标准输入的一种替代品,
可以帮助脚本开发人员不必使用临时文件来构建输入信息,而是直接就地生产出一个文件并用作命令的标准输入。
Here Document有一个非常重要的标识叫EOF——文件结束符号
即在使用Here Document实现免交互操作一个系统或文件的时候,需要借助EOF这个文件结束符号,来标志着你文件内容的开始与结束。
补充:
向左指的箭头——写入的意思,把内容写入到指定的文件里面。
>表示覆盖了原有的内容
>>表示在原有内容追加的意思
注:Here Document的基本语法格式为:
特殊字符<<在标记和命令之前,这样做的目的是将命令块的输出重定向到程序或命令的stdin;
标记的选择要确保不会出现在其他地方,以避免出现混淆;
两个标记之间的内容被当作是一个文件并用作命令的标准输入;
Here Document也可以与非交互式程序和命令一起使用。
补充:在实际使用过程中,要注意:标记可以使用任意的合法字符;
结尾的标记一定要顶格写,前面不能有任何字符;
结尾的标记后面也不能有任何字符(包括空格);
开头的标记前后的空格会被省略掉。
在Linux中系统中,使用wc-l命令后面直接跟文件名就可以统计文件内有多少行内容。
而采用Here Document免交互方式也可以实现对行数的统计,如下图所示:
1.2 Here Document免交互
通过Here Document可以将一些简单的交互任务的交互过程去除掉,尤其是在编写脚本的过程中。
(1)通过read命令接收输入并打印
通常使用read命令接收用户的输入值时会有交互过程,尤其是在脚本执行过程中遇到read命令,脚本会停下来等待用户输入值后才会继续。
例如,在下图中输入值是两个EOF标记之间的部分,也就是Hi,浙江作为变量i的值,在最后echo打印变量i的值,即最后会输出Hi:
执行上述脚本,输出结果如下图所示:
(2)通过passwd给用户设置密码
例如,通过passwd命令给jerry用户设置密码时,为避免重复交互,可使用Here Document的方式:
注:上图中,EOF标记之间的两行是输入的密码和确认密码,两行内容必须保持一致,否则密码设置不成功。
此脚本执行后不会输出任何信息,可打开另一个终端使用jerry用户登录,输入新修改的密码来验证是否修改正确。
1.3 Here Document变量设定
Here Document也支持使用变量,如果标记之间有变量被使用,会先替换变量值。
注:如果想要将一些内容写入文件,除了常规的方法外,也可以使用Here Document。
如果要写入的内容中包含变量,在写入文件时要先将变量替换成实际值,再结合cat命令完成写入。如下图:
在上图的执行过程中,标记内变量i的值被替换成了company,最终结果输出到$doc_file内,其值为2019.txt。
还可以用Here Document来进行变量的设定。Here Document不光可以将标记内容传给命令来执行,还可以将整体赋值给一个变量,然后通过echo命令将变量值打印出来。
在上图中,$ivar先进行了替换,之后再转向输出,交由cat显示出来,其结果放置到$()中,最后得到上述结果。
1.4 Here Document格式控制
Here Document支持两种控制输出格式的类型:关闭变量替换的功能、去掉每行之前的TAB字符。
(1)关闭变量替换的功能
关闭变量替换的功能就是希望按照字符原本的样子输出,不做任何修改或替换:
(2)去掉每行之前的TAB字符
在下图的例子中,每一行都有一个TAB字符。
注:在第1行的标记前加-,这个表示要抑制各行首TAB的作用。
1.5 Here Document多行控制
注:在Shell脚本的工作中,#右侧的任何字符串,bash都会将其忽略。
Here Document的引入解决了多行注释的问题,其语法格式如下:
在上图中,:表示什么都不做的空命令;
中间标记区域的内容不会被执行,会被bash忽略掉,因此可达到批量注释的效果。
下面的脚本用于演示Shell中的多行注释,开头的 Here Document标记内容不会被执行(在需要使用多行注释的时候可以采用此方法)
1.6 Here Document的应用
先用vim编辑器,打开一个aa.sh的脚本文件,然后在文件里写入下面的内容:
接着保存退出,执行一下:
若把vim编辑器里面的EOF右边的双箭头去掉一个,改成单箭头,然后执行一下,如下图:
若将vim编辑器里的EOF改成AAA,把数据中的第2行和第3行都改成191,再执行一下,如下图:
补充:这说明文件结束符EOF它仅仅是一个起始与结束的符号,至于这个符号你写成什么不重要,我们经常用EOF这三个字母,是因为EOF这三个字母它确实代表文件结束符这几个字的意思。(EOF是可以用别的词来代替的,因为它仅仅代表一个开头与结束的符号)
注意:文件结束符是可以嵌套的,正常的话,文件结束符中间应该是文本的内容,但是这些内容呢也可以再带一对文件结束符,就像引号套引号一样。
若想借助Here Document来统计文本中人名的数量,可执行下图中的命令:
补充:前面一个EOF,后面一个EOF,中间就确定了我的语句块。
所谓语句块是什么?
它是一组指令的集合,这个集合一定是被某一个控制语句所规范起来的。
使用read命令的-p选项,可以提示用户输入内容,然后把输入的内容赋值给变量name。如下图:
要求:使用read读取语句、字符串,然后把读到的内容赋值给变量。
那如果不想用上图的这种交互式界面,而想用非交互式的界面,怎么实现呢?
需要注意的是:
补充:
下面实现一种变量的替换方式:
先用vim编辑器打开一个空文件aa.sh,然后在aa.sh脚本文件里,填写下图中的内容。如下图:
上图中的EOF中间的语句块表示,写入这个文本的内容里包含一个变量,最终会把这个变量替换为对应的值,这个值是nihao。
补充:如何在vim编辑器里删除当前的所有内容?
先输入一个小写字母d,再输入一个大写字母G,整个内容就全删了。如下图:
法一:
法二:
先用vim编辑器打开一个脚本文件bb.sh,然后在里面输入下面的内容:
关于注释符的问题:
然后执行一下这个脚本可以得到如下图所示的结果:
但如果这7行中,有的若干行我不想看到,就可以在脚本中用注释符#给注释掉。那么如果说我们要注释掉的行数有很多(几十行甚至是上百行),也需要这样加很多的#吗?
那就可以使用Here Document进行多行注释,可以在脚本中执行下图中的命令:
然后保存并退出vim编辑器,去执行一下该脚本,如下图:
2、expect免交互
2.1 expect概述
expect是建立在tcl语言基础上的一个工具,它可以让一些需要交互的任务自动化地完成。相当于模拟了用户和命令行的交互操作。
注: expect是用来进行自动化控制和测试的工具,主要解决Shell脚本中不可交互的问题。
在Linux维护工作中,经常需要远程登录服务器进行操作。而登录的过程是一个交互的过程,可能会需要输入yes/no、password等信息。
为了模拟这种输入,可以使用expect脚本。
2.1.1 expect安装
Linux系统本身并没有安装 expect和tcl,需要手动安装。
2.2 、expect的应用
tcl——工具命令语言(并不是一种特定的编程语言),tcl只是一类语言的代称,并没有明确指明是什么语言。
expect有着它自己的语法结构,它就属于tcl语言。
注:Here Document是针对文本编辑内容进行免交互的,
那么不仅仅只是针对文本内容的编辑可以免交互的,我的命令行中输入的命令也是可以用脚本去实现免交互的。
例如,假如在192.168.10.101的主机上使用ssh命令远程登录到另一个主机192.168.10.103上的时候,会出现很多提示信息,要求输入登录账号密码相关的信息。如下图:
可以使用expect免交互去实现命令的免交互。
注:可以把安装的expect工具也当成一个特殊的解释器,它和bash解释器是一类的。bash解释器只不过解释的是操作系统的指令,而expect解释器解释的是expect所对应的指令。
expect所能执行的命令/解释的语句有:
(1)expect命令的功能
那么,如何让脚本自动去识别这一行是输入yes或no的呢?也就是说,如何让你的脚本去识别这行字符里有个你指定的字符或字符串?
就可以用expect去实现,expect主要是判断输出内容中,是否包含指定的字符串。
(2)send命令的功能
send是发送字符串的一个手段,命令也算字符串。
如下图,需要在提示内容后手动输入一个密码,而是要send命令可以用发送的方式给发送一个密码(也不用手动去敲了)。
(3)spawn命令的功能
可以实现开启一个会话的功能,通常在spawn后面可以跟一个系统命令。
注:任何开启一个交互式动作的命令,都可以用spawn去引出来。
平时正常的话要登录一个别的系统可以用ssh命令去登录,但是现在要交给expect免交互这个工具去读取,就可以在ssh+目标地址的前面加上一个spawn,如下图:
(4)expect eof命令和interact的功能
expect eof代表结束,而interact也代表结束。
注:这两个结束符号不能同时用,只能用其一,即不要连着用。
它们的区别在于:interact的结束只是结束了交互,不结束你的expect;
而expect eof的结束代表整个expect都结束了。
例如,要用ssh命令远程登录到一个主机上,如下图:
如果用的是interact这种方式去结束的话,意味着只是结束了ssh命令的登录交互动作,那结束交互之后停留在了远程主机的环境,就可以继续针对远程主机输入命令;
但如果说仅仅只是想实现一个免交互的动作,然后还想退回到原来的主机环境,即不再连接到102这个远程主机,那就可以用expect eof这种方式去结束,这就意味着整个expect就结束了。
案例1:如何使用expect以脚本的方式,用ssh登录远程主机?
因为当前系统里面是没有expect这个工具的,那就安装一个expect。如下图:
在bb.sh脚本里面按照下图中的填写:
然后保存退出vim编辑器,执行一下刚刚写的脚本,如下图:
注:在远程登录到主机192.168.10.100之前,要确保其是处于开机的状态。
因为刚才在脚本里面写的是interact退出方式,它的结束仅仅意味着ssh交互的结束,结束后还会停留在目标远程主机的环境上,所以此时的IP还是192.168.10.100。
但是如果此时想回到原来的主机上,可以执行一下exit指令,如下图:
但是如果要把脚本里的退出方式给换成expect eof这种退出方式的话,如下图所示:
改变过之后保存退出vim编辑器,然后再来执行一下该脚本:
注:在把退出方式换成expect eof以后,它把整个expect给退了出来,即不会再停留在目标主机100的远程环境上。
案例要求2:利用脚本登录到远程主机,在远程主机执行相应的指令,执行结束了以后,就退出远程主机的操作环境,回到当前的主机。
那根据上面的要求,直接在脚本中连接到远程主机的那一块命令之后添加相应的命令不就可以了吗?
在脚本bb.sh中按照下图编写:
然后执行一下:
改进脚本如下:
然后保存并退出vim编辑器,执行一下该脚本,如下图: