【shell】shell实现交互⽬录
⼀、SHELL
1.1 输⼊单个指令
⾃动输⼊yes
echo "y" | yum install wget ,等同于yum -y install wget
⾃动输⼊回车
echo -e "\n" | yum remove wget
**`echo -e` 的⼩知识**
若字符串中出现以下字符,则特别加以处理,⽽不会将它当成⼀般⽂字输出:
\a发出警告声;
\b删除前⼀个字符;
\c最后不加上换⾏符号;
\f换⾏但光标仍旧停留在原来的位置;
\v与\f 相同;
\n换⾏且光标移⾄⾏⾸;
\r光标移⾄⾏⾸,但不换⾏;
\t插⼊tab符号;
\\插⼊ ‘' 字符;
\nnn插⼊ nnn(⼋进制)所代表的 ASCII 字符;
1.2 输⼊多⾏指令
输⼊多⾏指令我们需要借助输⼊重定向操作符<<
以下⾯这个脚本为例
multi.sh
#!/bin/bash
read -p "enter number:" no
read -p "enter name:" name
echo "you have entered $no, $name"
借助<<;符号进⾏⾃动化输⼊
#!/bin/bash
sh multi.sh << EOF
1
shell脚本返回执行结果mutoe
EOF
但是有时候这种⽅法并不⽣效,⽐如ssh-keygen命令,那只有借助强⼤的expect命令了
read -p "you are sure you wang to xxxxxx?[y/n]" input
echo $input
if [ $input = "y" ];then
echo "ok "
fi
限制输⼊内容的个数
我们还可以使⽤ read命令的-n 选项,此选项后⾯需要接⼀个数字,可以限制输⼊内容的个数。#!/bin/bash
read -p "May I ask your name: " name
echo "Hello $name"
read -n1 -p "Press any key to exit"
echo
exit 0
控制输⼊内容的可见性
⽬前,我们输⼊的内容都是可见的,但有些敏感的数据,如密码,信⽤卡号等信息,输⼊时并不想可见。那么可以使⽤read -s。
这时再输⼊时,就有⼀个钥匙的标识,⽽且输⼊时不可见。
⼆、Expect
简介
expect是⼀个免费的编程⼯具,⽤来实现⾃动和交互式任务通信,安装yum install -y expect
Expect的语法:
关键命令send、expect、spawn和interact:
send:⽤于向进程发送字符串,注意⼀定要在末尾加\r回车
expect:从进程接收字符串
spawn:启动新的进程
interact:允许⽤户继续交互
expect 有两种⽤法,⼀种是直接写 expect 解释器的脚本,和 bash 类似,以#!/usr/bin/expect开头
下⾯是⼀个合格的 expect 脚本⽰例
#!/bin/expect
set IP [lindex $argv 0] # 读取第1个参数设置为 IP 变量
set PASSWD [lindex $argv 1] # 读取第2个参数设置为 PASSWD 变量
set CMD [lindex $argv 2] # 读取第3个参数设置为 CMD 变量
spawn ssh $IP $CMD # spawn 来给命令加壳,以便于断⾔输出
expect { # expect 是断⾔命令
# 如果读取到屏幕上输出 (yes/no) 信息,则输⼊ "yes" 并按下回车键
# exp_continue 是继续等待花括号内的断⾔, 如果不加这⼀句会直接跳出 expect
"(yes/no)?" { send "yes\r"; exp_continue }
"password:" { send "$PASSWD\r" } # 如果读取到屏幕上输出 password 信息,则输⼊ PASSWD 变量中的内容
"*host " { exit 1 } # 如果读取到 "No route to host" 等内容,就以⾮0状态退出
}
expect eof # 等待命令执⾏结束
需要注意的是,在 expect 解释器内,除了⼏个特定关键字的命令,其他命令都不可⽤,这种⽅式适⽤于执⾏命令较少,单次需要交互较多的⾃动化脚本
第⼆种⽤法是在 bash 脚本中执⾏ expect 配合重定向操作符, 在有⼤量脚本需要执⾏的情况下推荐使⽤该⽅式
下⾯是我在certbot命令时使⽤的 shell 脚本,以供参考
#!/bin/bash
sudo expect << EOF
spawn certbot --nginx
expect {
"Enter email address" { send "mutoe@foxmail\n";exp_continue}
"Please read the Terms of Service" {send "A\n";exp_continue}
"Would you be willing to share your email address" {send "N\n";exp_continue}
"Which names would you like to activate HTTPS for" {send "\n";exp_continue}
"You have an existing certificate that has exactly the same domains" {send "1\n";exp_continue}
"Please choose whether or not to redirect HTTP traffic to HTTPS" {send "2\n";exp_continue}
eof
}
expect是关键的部分,在英⽂中,expect有“期待”的意思,采⽤了tcl的模式-动作语法,此语法有以下⼏种模式:
单⼀分⽀语法:
expect "hello" {send "you said hello"}
多分⽀模式语法:
expect {
"hello" {send "hello\r"; exp_continue}
"world" {send "world\r"; exp_continue}
"how are you ?" {send "Fine,thanks\r"}
}
实例
SSH登录
例:expect脚本p内容:
#!/usr/bin/expect
set timeout 2
spawn ssh wan@10.229.130.107
expect {
"[Pp]assword" {send "123456\r";}
"[Yy]es/no" {send "yes\r";exp_continue}
}
.
..
...
...
send "exit\r"
exit 0
#send:⽤于向进程发送字符串,注意⼀定要在末尾加\r回车
#expect:从进程接收字符串
#spawn:启动新的进程
#interact:允许⽤户继续交互
FTP⽂件同步
经常要⾯临在某个环境编辑代码然后需要⾃动同步更新到其他机器的情况。对于这种问题,我们也可以借助expect脚本来实现。
例:
配置⽂件为sync.cfg:
#","分隔的内容分别为需要同步的⽂件、⽬标路径和⽬标主机密码
/home/long/tmp/*.py,wan@10.229.130.107:/home/wan/tmp,123456
shell脚本sync_ftp.sh内容:
#!/bin/bash
#读取配置信息
for line in `cat sync.cfg`
do
#删除存在的信息⽂件,避免数据污染
if [ -f info.dat ]
then
rm -rf info.dat
fi
touch info.dat
#获取路径和密码
srcaddr=`echo $line | cut -d , -f 1`
destaddr=`echo $line | cut -d , -f 2`
passwd=`echo $line | cut -d , -f 3`
#查指定⽇期需要同步的⽂件
for tmp_file in `find $srcaddr -mtime 1 -type f`
do
echo $tmp_file >> info.dat
done
#调⽤expect脚本进⾏同步
expect p $destaddr $passwd
#判断是否同步成功
if [ $? -eq 0 ]
then
rm -rf info.dat
echo "all success!"
else
echo "sync $destaddr fail!"
fi
done
exit 0
expect脚本p:
#!/usr/bin/expect
set timeout 20
#读取输⼊参数
set remotehost [lindex $argv 0]
set remotepass [lindex $argv 1]
#启动新进程,运⾏sftp协议
spawn sftp $remotehost
expect "[Pp]assword*"
send "$remotepass\r"
#发送⽂件
expect "sftp>"
set content [ open info.dat ]
while { [ gets $content local_file ] != -1 }
{
send "put $local_file\r"
expect "sftp>"
}
send "exit\r"
exit 0
由于⽂件同步是每天都需要进⾏的,因此可以结合定时任务crond来进⼀步简化⼯作。crond是类unix系统下⽤来周期执⾏某种任务或者事件的⼀个守护进程,配置信息存放在/etct/crontab⽂件中。crontab是系统服务crond的控制命令。关于crontab的使⽤,在进程章节已经进⾏了介绍,这⾥就不再赘述了。
Expect命令是很强⼤的,可以实现各种⾃动化操作。⾃此,你不仅可以写出各种厉害的shell脚本,还能让它们⾃动执⾏,对于⽇常⼯作的处理将会有⼤⼤的提升。
原⽂:
注:expect命令
[set timeout 30]
基本上认识英⽂的都知道这是设置超时时间的,现在你只要记住他的计时单位是:秒
[spawn ssh -l username 192.168.1.1]
spawn command命令会fork⼀个⼦进程去执⾏command命令,然后在此⼦进程中执⾏后⾯的命令;
spawn是进⼊expect环境后才可以执⾏的expect内部命令,如果没有装expect或者直接在默认的SHELL下执⾏是不到spawn命令的。所以不要⽤ “which spawn“之类的命令去spawn命令。好⽐windows⾥的dir就是⼀个内部命令,这个命令由shell⾃带,你⽆法到⼀个dir 或 的可执⾏⽂件。
它主要的功能是给ssh运⾏进程加个壳,⽤来传递交互指令。
[expect "password:"]
这⾥的expect也是expect的⼀个内部命令,有点晕吧,expect的shell命令和内部命令是⼀样的,但不是⼀个功能,习惯就好了。这个命令的意思是判断上次输出结果⾥是否包含“password:”的字符串,如果有则⽴即返回,否则就等待⼀段时间后返回,这⾥等待时长就是前⾯设置的30秒
[send "ispass\r"]
这⾥就是执⾏交互动作,与⼿⼯输⼊密码的动作等效。
温馨提⽰:命令字符串结尾别忘记加上 “\r”,如果出现异常等待的状态可以核查⼀下。
[interact]
执⾏完成后保持交互状态,把控制权交给控制台,这个时候就可以⼿⼯操作了。如果没有这⼀句登录完成后会退出,⽽不是留在远程终端上。如果你只是登录过去执⾏⼀段命令就退出,可改为[expect eof]
expect可以让你使⽤“-c”选项,直接在命令⾏中执⾏它,例如:
expect -c '
spawn git pull
expect {
"Usernam*" {send "code_manager@ren001\n"; exp_continue }
"Passwor*" {send "$GIT_CODE_PASSWORD\n" ; exp_continue}
}
'
原⽂链接:blog.csdn/appke846/article/details/80513099
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论