近日,在安装某软件过程,发现在安装过程需要输入一些信息才能继续下一步操作,在机器数量较少情况下,我们可以单台登录上去完成安装操作,但当机器数量超过一定时,如果再手动登录操作,就会产生大量重复性操作,既不能带来有效学习能力提升,同时也会极大产生不确定性,引发工作效率下降,那么如何自动化完成某些操作呢,尤其是带有交互功能的步骤呢,例如需要输入账号密码?
如有兴趣转载,请标注来源:https://www.cnblogs.com/xiong97/p/16557437.html 谢谢!
新交付了一批机器,每台机器只分配了一块落盘 ,现在根据需求对该盘进行分区并实现挂载,如何实现?
对于一个盘,实现分区挂载到不同目录,通常思路有两条:
这里我们为了演示交互功能,选择方法二,实现脚本如下:
#!/bin/bash
fdisk /dev/sdb <<EOF
n
p
1
wq
EOF
mkfs.xfs /dev/sdb1 && mkdir -p /data && mount /dev/sdb1 /data
echo '/dev/sdb1 /data xfs defaults 0 2' >> /etc/fstab
分析上述脚本,我们发现使用了 一个关键字 EOF
EOF是END Of File的缩写,表示自定义终止符.既然自定义,那么EOF就不是固定的,可以随意设置别名,在linux按ctrl-d就代表EOF.EOF一般会配合cat能够多行文本输出.
其用法如下:
<<EOF //开始
.... //需要输入的内容
EOF //结束
例如使用 cat、<<、EOF和>以交互方式编写bash脚本,如下所示。
cat << EOF > script.sh
#!/bin/bash
printf "Hello\n"
printf "Wordl!\n"
EOF


合理 利用这三个,即可以完成对应多文本交互输入,例如修改用户密码,正常情况下,需要连续输入两次密码,两次密码一致才能修改成功,如下:

上面我们学会了EOF 这个关键字,那么我们试试通过它来修改密码。脚本如下:
#!/bin/bash
cat << EOF| passwd
新密码
新密码,与上述需一致
EOF
# or 不使用管道符
passwd << EOF
新密码
新密码,与上述需一致
EOF
实战结果,成功修改密码:

新交付了一批机器,需要给每台机器分发文件,如何实现?
远程拷贝文件常用密令是scp 或者 rsync ,但是在给每台机器传输时需要若输入密码,有的机器可能还需要输入YES,录入机器指纹信息,如下:

Expect 是在tcl基础上的一个自动化交互套件, 在一些需要交互输入指令的场景下, 可通过脚本设置自动进行交互通信. 其交互流程主要有以下5步:
0 定义变量
1 spawn启动指定脚本或命令
2 expect匹配结果关键词
3 send针对指定关键词发送指定指令
4 执行完成, 退出
但可惜的是os默认没有安装,因此需要先安装才能使用
Expect is a tcl application for automating and testing interactive applications such as telnet, ftp, passwd, fsck, rlogin, tip, etc. Expect makes it easy for a script to control another program and interact with it.
1. 先检查本机是否安装了expect ,如果没有安装,需要手动安装
# 检查是否安装了expect:
[root@localhost ~]# rpm -qi expect
Name : expect
Version : 5.45
Release : 14.el7_1
Architecture: x86_64
Install Date: Fri 05 Aug 2022 07:26:04 AM CST
Group : Development/Languages
....
# 如果没有安装, 使用yum安装expect ,通常会顺带把依赖包tcl 也安装了:
[root@localhost ~]# yum install -y expect # -y 其实也是安装过程中一个交互,发现没,只是作为参数传入了
[root@localhost ~]# yum install -y tcl # 如果上述命令提示已安装tcl了,此步可以忽略
# 查看expect的安装路径:
[root@localhost ~]# which expect
/usr/bin/expect
2 .对应功能脚本开发,本案例脚本参考如下:
[root@test01 ~]# cat scp.exp
#! /usr/bin/expect
set file [lindex $argv 0]
set file2 [lindex $argv 1]
spawn scp -rp $file $file2 root@192.168.31.89:/tmp
expect {
"(yes/no)" {send "yes\r";exp_continue}
"*password:*" {send "Password\r"}
}
expect eof
exit -onexit {
send_user "bye \n"
}
3. 分析上述脚本,有几个点需要说明
#!/usr/bin/expect
脚本文件的第一行指明expect 安装位置,具体可以参考2 中命令查看,指明脚本解析器,和Shell类似,表示程序使用Expect解析,这里与一般bash 脚本不同,因此需要注意,通常我们会将expect脚本后缀修改成exp来和bash 脚本 sh区别
set file [lindex $argv 0] 将传入的第一个参数赋给file ,类似第二、三个参数[lindex $argv 1] [lindex $argv 2] 等,后续调用时使用 $file ,和shell 一样。特殊参数:
$argc表示传参的个数,$argv0表示脚本的名字
格式: spawn [选项] [需要自动交互的命令或程序]
例如:spawn scp -rp $file $file2 root@192.168.31.89:/tmp #<==执行scp命令(注意开头必须要有spawn, 否则无法实现交互)
需和spawn 配合使用 ,表示匹配spawn指定的脚本或命令的输出结果,如果与expect后面的字符串匹配,就执行下面的send命令,表示对结果响应反馈
有时命令的输出提示信息有可能会变化,所以可以在expect中使用模糊匹配,比如*。
注意:匹配的动作也可以放在下一行,这样就不需要使用{}(大括号)了
在expect命令匹配指定的字符串后,发送指定的字符串给系统,这些命令可以支持一些特殊转义符号,例如:\r表示回车、\n表示换行、\t表示制表符等
从命令的拼写就可以看出命令的作用,即让Expect程序继续匹配的意思,如果需要一次匹配多个字符串,那么不同的匹配之间就要加上exp_continue,否则expect将不会自动输入指定的字符串。最后一个的结尾就不需要加上exp_continue了,因为前面都已完成了,它是最后一个啦
功能类似于Shell中的exit,即直接退出脚本,还可以利用这个命令对脚本做一些关闭前提示等工作
打印Expect脚本信息,类似Shell里的echo. 例如打印变量信息,验证数据传入是否正常
在掌握expect 基本使用方式后,我们写一个批量查看机器负载信息的小脚本,加强记忆
#! /usr/bin/expect
set time 30
set ip [lindex $argv 0]
spawn ssh root@$ip uptime
expect {
"*yes/no" { send "yes\r"; exp_continue }
"*password:" { send "$password\r" }
}
expect eof
实战结果:

在学习完以上两个方法,我们试着写一个脚本,结合上述两种方式,批量查看各机器目录挂载情况,并列举出来,参考脚本如下:
#!/bin/bash
ip="192.168.31.89"
username="root"
password="123456"
cmd=" df -PTh|grep ^/dev"
# 指定执行引擎
expect <<EOF
set time 30
spawn ssh $username@$ip $cmd
expect {
"*yes/no" { send "yes\r"; exp_continue }
"*password:" { send "$password\r" }
}
expect eof
EOF
以上两种方式就是日常在Linux Shell 脚本常用来做自动化部署,解决脚本执行过程参数交互问题,尤其expect 配合一些shell脚本执行,十分便捷。除了以上使用方式,在企业生产中,我们还会用到ansible 脚本,ansible是新出现的自动化运维工具,基于Python开发,通过调用其模块,实现批量系统配置、批量程序部署、批量运行命令等功能,有兴趣的小伙伴可以试试学习下。
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式rubyshell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建
我想知道是否可以通过自动创建数组来插入数组,如果数组不存在的话,就像在PHP中一样:$toto[]='titi';如果尚未定义$toto,它将创建数组并将“titi”压入。如果已经存在,它只会推送。在Ruby中我必须这样做:toto||=[]toto.push('titi')可以一行完成吗?因为如果我有一个循环,它会测试“||=”,除了第一次:Person.all.eachdo|person|toto||=[]#with1billionofperson,thislineisuseless999999999times...toto.push(person.name)你有更好的解决方案吗?
在我的一些Controller中,我有一个before_filter检查用户是否登录?用于CRUD操作。application.rbdeflogged_in?unlesscurrent_userredirect_toroot_pathendendprivatedefcurrent_user_sessionreturn@current_user_sessionifdefined?(@current_user_session)@current_user_session=UserSession.findenddefcurrent_userreturn@current_userifdefine
文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3