Linux 脚本自动交互

今天学习 Linux 脚本自动交互。需要完成 IP 归属地数据文件的维护,而 gmaker 工具里面有交互命令,现在想用脚本替代手动输入。

在我们日常的 Linux 指令中,有很多命令提供交互式操作,例如 sudo、ssh、ftp 等,如何使用脚本完成自动交互呢?

1,使用重定向

重定向是将标准输入输出进行重定向操作,例如将标准输入输出重定向到文件。用重定向标准输入到文件的前提,是命令支持有参数指定输入方式,如 ftp 就有-i 参数来指定使用标准输入来输入密码。

shell 使用重定向标准输入的方法有:

command < file 将输入重定向到file

命令交互式重定向

command << delimiter
    document
delimiter

shell 会将分界符 delimiter 之间的内容作为输入。

例如,我们来使用 ftp 实现自动登录并运行 ls 的脚本,其中用户名为 test,密码为 123456。

ftp -i -n 192.168.1.10 <<EOF
user test 123456
ls
EOF

2,使用管道

管道命令使用|这个符号,它会将前一个命令的输出作为下个命令的输入。它也需要命令支持。

例如,实现 sudo 自动输入密码的脚本:

echo '123456' | sudo -S cp file1 /backup/file1

其中,123456 是密码。

3,使用 expect 工具

expect 是用来做交互,基本任何交互的场合都能使用。在像 ssh 命令没有指定输入的参数,就很适合这种方式。

需要先安装 expect,安装命令如下:

yum install expect

例如:我们使用 ssh 远程登录某台服务器的脚本

#!/usr/bin/expect

set timeout 30
spawn ssh -l root 192.168.1.10
expect "password*"
send "123456\r"
interact

其中, 第一行是脚本执行引擎,第二行设置超时 30 秒,第三行执行 ssh 登录,spawn 是 expect 内部命令,意思是启动一个新的交互进程后面跟命令或者指定程序,第四行匹配 password 关键字,如果匹配到往下继续执行,只有 spawn 执行的命令结果会被 expect 捕捉到。如果捕获到立即返回,否则等待超时后返回,超时时间在第二行设置了。expect "#*" 或"]#"代表匹配任何内容。第五行发送密码,相当于手动输入密码。send 是 expect 内部命令,会将密码输入到 spawn 启动的进程中,第六行进入交互模式,留在远程控制台,如果没有这句就返回本地控制台。

附上 expect 常用命令

命令说明
spawn启动新的交互进程后面跟命令或者指定程序
expect从进程接收消息,如果匹配成功,就执行 expect 后的动作
send向进程发送字符串
send exp_send用于发送指定的字符串信息
exp_continue在 expect 中多次匹配就需要用到
send_user用来打印输出
interact允许用户交互
exit退出 expect 脚本
eofexpect 执行结束,退出
set定义变量
puts输出变量
set timeout设置超时时间

下面,我们来实现我们的脚本,用来自动更新我们的 IP 源。

#!/bin/bash

change_num=`wc -l ipchange.txt|awk '{print $1}'`

if [ $change_num == 0 ]
then
    echo "file is empty"
    exit
fi

expect <<EOF
    set timeout 10
    spawn gmaker edit --src=ip.merge.txt
    expect "editor*" {send "put_file ipchange.txt\n"}
    expect "editor*" {send "save\n"}
    expect "editor*" {send "quit\n"}
    expect "#*" {send "exit\n"} expect eof
EOF

sleep 1
cat /dev/null>ipchange.txt
gmaker gen --src=ip.merge.txt --dst=ip2region.xdb

经实测,可用。