免交互
交互:我们发出指令控制程序的运行,程序在接收到指令之后按照指令的效果做出对应的反应。
免交互:间接的,通过第三方的方式把指令传送给程序,不用直接的下达指令。
一、Here Document 免交互:
这是命令行格式,也可以写在脚本当中。通过i/o重定向的方式将命令的列表传送给交互式程序或目命令。
是标准输入的一种替代品。代替了人工的输入方式。
1.1、语法格式:
命令 (linux的系统命令) <<标记
内容1
内容2
内容3
标记
less[root@test1 opt]# wc -l <<xy102 > 123 > 234 > 456 > xy102 > 3
[root@test1 ~]# wc -l <<xy > 1 > 2 > 3 > 4 > 5 > xy > 5
1.2、注意事项:
1、标记可以任意合法字符(一般不用特殊字符,不以数字开头,通常用以EOF作为默认的标记位)
2、结尾的标记一定要顶格写。且前面不能有任何字符,空格也不行。
3、结尾的标记后面也不能有任何字符,包括空格。
1.3、免交互之重定向:
[root@test1 opt]# read i <<EOF TES EOF [root@test1 opt]# echo $i TES [root@test1 opt]# passwd ly <<EOF > 123 > 123 > EOF > 更改用户 ly 的密码 。 > 新的 密码:无效的密码: 密码少于 8 个字符 > 重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
[root@test1 opt]# cat <<EOF>>test3.txt #>>追加 > 123 > abc > ABC > EOF > [root@test1 opt]# cat test3.txt > 1 www.kgc.com > 2 mail.kgc.com > 3 ftp.kgc.com > 4 linux.kgc.com > 5 blog.kgc.co > 123 > abc > ABC
[root@test1 opt]# tee test3.txt <<EOF #<<覆盖 > 456 > 654 > EOF > 456 > 654 > [root@test1 opt]# cat test3.txt > 456 > 654
1.3、cat > $a <<EOF以及cat <<EOF引入变量值
file="test4.sh"
i=school
cat > $file <<EOF #变量值引入file--test4.sh
I am going to $i
EOF
[root@test1 opt]# cat > test ##在此基础上进行重定向输入到文件中;
asasa
sad
asd
asd
fss
[root@test1 opt]# cat > test <<EOF
> 123
> 234
> EOF
[root@test1 opt]# cat <<EOF > 123 > 1234 > 345 > 2314 > EOF > 123 > 1234 > 345 > 2314 ##相当于cat一个文件,文件里面包含这些内容。免交互形式的写入内容
less
[root@test1 opt]# vim test3.sh
#整体变量赋值
var="Great! i am going to sschool"
myvar=$(cat <<EOF
THIS is monday
$var ##=Great! i am going to sschool
EOF
)
echo $myvar
[root@test1 opt]# sh test3.sh
THIS is monday Great! i am going to sschool
关闭EOF后,EOF内部变量失效变成字符串。
less
[root@test1 opt]# vim test3.sh
var="Great! i am going to sschool"
myvar=$(cat <<'EOF'
THIS is monday
$var
EOF
)
echo $myvar
[root@test1 opt]# sh test3.sh
THIS is monday $var
[root@test1 opt]# cat <<'EOF'
THIS is monday
$var
EOF
THIS is monday
$var
[root@test1 opt]# cat <<EOF##相当于cat一个文件,文件里面包含这些内容。
THIS is monday
$var
EOF
THIS is monday
二、Expect实现免交互
用tcl语言写的一个工具,主要用自动化控制和测试,解决shell脚本交互的问题。
转义符:
\n:换行
\r:回车
\t:相当于tab键
\b:表示退格,删除
需要安装软件
2.1、Expect免交互实现用户密码更改
less
[root@test1 opt]# vim passwd
#!/usr/bin/expect
#声明解释器,不再是默认的bash。需要声明
#set设置,timeout超时时间,expect有默认超时时间是10秒,设置超时时间5秒。
#set也可以作为设置变量
spawn passwd ly
#spawn 后面用来声明需要执行的命令,开启会话过程,并且跟踪后续的交互信息。
expect "新的*"
#捕获需要执行的命令行,只要能捕获就行,不需要完整的,可以*代表所有
send "123\r"
#输入指令代码
expect "重新输入新的 密码:"
send "123\r"
#最后一定要有结束语,结束语只能写一个
expect eof
#交互指令结束之后,会退回原用户,5秒之后切换回原用户
#interact
#留在当前用户,不会动
[root@test1 opt]# chmod 777 passwd
[root@test1 opt]# ./passwd
spawn passwd ly
更改用户 ly 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
[root@test1 opt]#
2.2、expect位置传参-----interact留在当前用户
less
#!/usr/bin/expect
#声明解释器,不再是默认的bash。需要声明
set timeout 5
set username [lindex $argv 0]
set password [lindex $argv 1]
#这种方式是位置变量
#开始追踪
spawn su - $username
#免交互开始执行
expect "密码"
send "$password\r"
#继续捕获
expect "~]$"
send_user "ok"
#send_user = echo 打印指定内容
#结束语
interact
结果
[liyang@test1 ~]$ ./test1.sh ly 123
spawn su - ly
密码:
上一次登录:三 6月 26 00:55:13 CST 2024pts/3 上
[ly@test1 ~]$ ok
expect eof留在当前用户
less
#!/usr/bin/expect
#声明解释器,不再是默认的bash。需要声明
set timeout 5
set username [lindex $argv 0]
set password [lindex $argv 1]
#这种方式是位置变量
#开始追踪
spawn su - $username
#免交互开始执行
expect "密码"
send "$password\r"
#继续捕获
expect "~]$"
send_user "ok"
#send_user = echo 打印指定内容
#结束语
#interact
expect eof
结果:
[root@test1 opt]# ./passwd ly
spawn su - ly
上一次登录:二 6月 25 11:19:38 CST 2024pts/3 上
[ly@test1 ~]$
[ly@test1 ~]$ ok[root@test1 opt]#
[liyang@test1 ~]$ ./test1.sh ly 123
spawn su - ly
密码:
上一次登录:三 6月 26 00:47:40 CST 2024pts/2 上
[ly@test1 ~]$ ok[liyang@test1 ~]$
三、嵌入模式
3.1、/bin/bash嵌入模式
less
#嵌入执行模式,在shell当中加入expect,涉及到环境切换的场景不建议使用嵌套。
#ssh su不适合使用嵌入模式
#!/bin/bash
user=$1
password=$2
#非交互指令,使用的是shell
useradd $user
#嵌入免交互
/usr/bin/expect <<-EOF
spawn password $user
expect "新的*"
send "$password\r"
expect "重新*"
send "$password\r"
expect eof
EOF
[root@test1 opt]# ./qiantao zq 123
spawn passwd zq
更改用户 zq 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
3.2、expect脚本内参数赋值
less
[root@test1 opt]# vim ssh.sh
#!/usr/bin/expect
set ip 192.168.168.20 #相当于内部写入参数的值,spawn命令执行,直接使用。
set user root ##此处规定了用户和密码
set password 123
set timeout 5
#进入命令行:
spawn ssh $user@$ip
expect {
"yes/no" {send "yes\r";exp_continue}
#这里捕获两次,表示该项被匹配之后,继续匹配其他的指定内容。类似于循环的continue,允许。
"password" {send "$password\r"}
}
interact
[root@test1 opt]# chmod 777 ssh.sh
[root@test1 opt]# ./ssh.sh
spawn ssh root@192.168.168.20
The authenticity of host '192.168.168.20 (192.168.168.20)' can't be established.
ECDSA key fingerprint is SHA256:yaufdRU2oi//z+PpV7wdWdPdTdEZT2SrypnKy30CsdY.
ECDSA key fingerprint is MD5:85:b0:7c:f3:f0:3a:95:f0:25:19:47:f4:90:46:bc:f5.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.168.20' (ECDSA) to the list of known hosts.
root@192.168.168.20's password:
Last login: Tue Jun 25 13:47:39 2024 from 192.168.168.11
[root@localhost ~]#
[root@test1 opt]# vim ssh.sh
[root@test1 opt]# ./ssh.sh
spawn ssh root@192.168.168.20
root@192.168.168.20's password:
Last login: Tue Jun 25 13:57:00 2024 from 192.168.168.10
3.3、expect脚本外部传参
less
#!/usr/bin/expect
set timeout 5
set hostname [lindex $argv 0]
set password [lindex $argv 1]
#进入命令格式:
spawn ssh $hostname
expect {
"No route to host {send_user "主机名/ip有误\n"}
"Connection refused" {send_user "ssh连接拒绝\n"}
"(yes/no)" {send "yes\r";exp_continue}
"password" {send "$password\r"}
}
interact
[root@test1 opt]# ./ssh1.sh root@192.168.168.20
spawn ssh root@192.168.168.20
root@192.168.168.20's password:
Last login: Tue Jun 25 14:02:19 2024
[root@test1 opt]# ./ssh1.sh root@192.168.168.30
spawn ssh root@192.168.168.30
ssh: connect to host 192.168.168.30 port 22: No route to host
spawn_id: spawn id exp6 not open
while executing
"interact"
(file "./ssh1.sh" line 15)
[root@test1 opt]# ./ssh1.sh root@192.168.168.30
spawn ssh root@192.168.168.30
The authenticity of host '192.168.168.30 (192.168.168.30)' can't be established.
ECDSA key fingerprint is SHA256:yaufdRU2oi//z+PpV7wdWdPdTdEZT2SrypnKy30CsdY.
ECDSA key fingerprint is MD5:85:b0:7c:f3:f0:3a:95:f0:25:19:47:f4:90:46:bc:f5.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.168.30' (ECDSA) to the list of known hosts.
root@192.168.168.30's password:
Last login: Tue Jun 25 14:17:43 2024 from 192.168.168.11
四、作业:
#免交互实现硬盘分区,分一个区即可,第一步要格式化,第二部实现挂载,挂载(手动挂载),然后再这个分区的挂载创建一个文件,写入内容"学习真好",并且打印结果。
#在一个脚本里完成,嵌入模式。
less
#免交互实现硬盘分区,分一个区即可,第一步要格式化,第二部实现挂载,挂载(手
动挂载),然后再这个分区的挂载创建一个文件,写入内容"学习真好",并且打印结>果。
#在一个脚本里完成,嵌入模式。
#!/bin/bash
#非交互指令
#免交互指令
/usr/bin/expect <<-EOF
spawn fdisk /dev/sdb
expect "命令(输入 m 获取帮助):"
send "n\r"
expect "Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p):"
send "p\r"
expect "分区号 (1-4,默认 1):"
send "1\r"
expect "起始 扇区 (2048-41943039,默认为 2048):"
send "\r"
expect "Last 扇区, +扇区 or +size{K,M,G} (2048-41943039,默认为 41943039):
"
send "+5G\r"
expect "命令(输入 m 获取帮助):"
send "w\r"
expect eof
EOF
mkfs.xfs -f /dev/sdb1
if [ $? -eq 0 ]
then
echo "分区创建成功"
mkdir /opt/data
mount /dev/sdb1 /opt/data
cd /opt/data
echo "学习真好" > file
cat file
else
echo "分区或文件系统创建失败"
fi
[root@test1 opt]# ./fenqu.sh
spawn fdisk /dev/sdb
欢迎使用 fdisk (util-linux 2.23.2)。
更改将停留在内存中,直到您决定将更改写入磁盘。
使用写入命令前请三思。
命令(输入 m 获取帮助):n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
分区号 (1-4,默认 1):1
起始 扇区 (2048-41943039,默认为 2048):
将使用默认值 2048
Last 扇区, +扇区 or +size{K,M,G} (2048-41943039,默认为 41943039):+5G
分区 1 已设置为 Linux 类型,大小设为 5 GiB
命令(输入 m 获取帮助):w
The partition table has been altered!
Calling ioctl() to re-read partition table.
正在同步磁盘。
meta-data=/dev/sdb1 isize=512 agcount=4, agsize=327680 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0, sparse=0
data = bsize=4096 blocks=1310720, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
分区创建成功
学习真好