@babydragon
2016-01-12T22:14:31.000000Z
字数 3019
阅读 3230
原创
工具
之前为了能够处理命令交互,编译了静态链接的expect,结果遇到了大问题导致在没有tcl的机器上还是无法运行。找了半天,发现empty是一个不错的替代。
首先,empty是一个纯C实现的,不依赖任何其他库的工具。这对于需要在不同机器上分发执行非常关键,之前expect就是因为无法确保机器上都有tcl或者其初始化脚本,导致无法使用。
其次,empty使用非常简单,可以方便的嵌入到shell脚本中,而无须像expect那样使用单独的脚本。这能够大大降低学习成本和后续维护成本。
empty和一般应用安装方式类似,直接make
即可。整个源码包中核心只有一个C文件,结构非常简单。下载地址在:http://sourceforge.net/project/showfiles.php?group_id=136798 这里。安装方式可以参考项目首页命令。
编译完成之后,就可以直接使用empty这个可执行程序了。它的help输出不是很友好,比较简单,大致参数有这几个:
因此,大部分场景下,先通过-f启动命令,然后通过-w命令监视输出,并且写入结果。例如代码中的示例,如果要模拟ssh登录,可以这样:
ssh="ssh" # (/full/path/to/)ssh
target="localhost" # target host
login="luser" # username (Change it!)
password="TopSecret" # password (Change it!)
fifo_in="/tmp/empty.in" # input fifo
fifo_out="/tmp/empty.out" # output
# -----------------------------------------------------------------------------
cmd="$ssh $login@$target"
tmp="/tmp/empty.tmp" # tempfile to store results
echo "Starting empty"
empty -f -L $tmp -i $fifo_in -o $fifo_out $cmd
if [ $? = 0 ]; then
if [ -w $fifo_in -a -r $fifo_out ]; then
echo "Sending Password"
empty -w -v -i $fifo_out -o $fifo_in -t 5 assword: "$password\n"
echo "Sending tests"
empty -s -o $fifo_in "echo \"-- EMPTY TEST BEGIN --\"\n"
empty -s -o $fifo_in "uname -a\n"
empty -s -o $fifo_in "uptime\n"
empty -s -o $fifo_in "who am i\n"
empty -s -o $fifo_in "echo \"-- EMPTY TEST END --\"\n"
echo "Sending exit"
empty -s -o $fifo_in 'exit\n'
echo "Check results:"
sleep 1
cat $tmp
rm -f $tmp
else
echo "Error: Can't find I/O fifos!"
return 1
fi
else
echo "Error: Can't start empty in daemon mode"
return 1
fi
echo "Done"
这么一大堆脚本,其实就三行和empty使用有关,一个是empty -f -L $tmp -i $fifo_in -o $fifo_out $cmd
,该命令执行ssh命令,并且指定输入、输出和日志文件。empty -w -v -i $fifo_out -o $fifo_in -t 5 assword: "$password\n"
该命令通过监听ssh命令的输出,如果遇到“assword:”字样,则向ssh进程发送密码。注意,这里的-i和-o参数和之前相反,因为需要监听ssh命令的输出,向ssh命令的输入发送字符。最后就是empty -s -o $fifo_in "echo \"-- EMPTY TEST BEGIN --\"\n"
这时ssh已经认证成功了,因此就直接向远程写入通过ssh执行的命令即可。
除了这种预先知道命令每一步的输出之外,还有一些场景是命令可能在有些场景下会进行交互,有些场景下不会。我们遇到的场景就是webx提供的autoconfig命令。该命令默认会在缺少配置项的时候进行交互,提示用户是否使用默认值,并且写入到antx.properties文件。
这时,就不能简单的通过每一步等待特定的字符,然后输出了。这里我们利用了empty的另一个特性,即自动维护管道文件,命令开始执行时,empty会创建对应的标准输入和标准输出两个管道文件,命令结束时删除,这样就不用用户来维护命令的输入输出,也不会产生垃圾文件。因此,我们可以通过循环的方式,监听是否有我们需要的关键字,在每次监听前,增加判断管道文件是否存在,以防止命令已经正常退出。大致的脚本如下:
empty -f -i input -o output -L $HOME/autoconfig.log autoconfig -u $HOME/antx.properties $f
sleep 1
while true;
do
if [ -w input -a -r output ]; then
empty -w -i output -o input -t 5 ".*\Yes.*" "yes\n" ".*\[Quit.*" "quit\n"
else
break;
fi
done
while循环里面,首先需要判断的是input和output两个文件是否存在。对于input文件,通过-w检查文件是否存在的同时,检查文件是否可写;对于output文件,通过-r检查文件是否存在的同时,检查文件是否可读。如果两个文件都存在,那么运行empty命令,等待输出并且设置超时时间。
这样的实现有两个好处,首先是可以兼容命令正常运行的流程,即无须进行交互。其次是不需要知道命令当前的状态,我们在一个empty命令里面已经兼容了命令所有可能的输出对应的用户输入值。