前言为了参与的这个讨论,整理一下以前写的脚本。现在看来,这个脚本写的很简陋,并发操作也只是分批的控制而不是完全的并行,不过工作起来还算简单稳定。
概述此脚本使用 expect 来对需要交互输入用户名和密码等操作进行自动化,并有对于主机提示自动加入信任列表、操作失败记录日志等功能。
正文这个脚本分三个文件,逐一附录如下:
1. 主脚本:batch_ssh
.sh
- #!/bin/bash
- # batch_scp.sh
- # 作者:亚丹
- # 时间:2009-05-27
- # seesea2517#gmail*com
- # http://seesea.blog.chinaunix.net
- # http://blog.csdn.net/nicenight
- #
- # 功能:批量无交互scp操作
- #
- # 配置文件格式:
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- server_list=$1
- cmd=$2
- if [ -z "$server_list" ] || [ -z "$cmd" ]
- then
- echo "Usage: $0 server_list command"
- exit 1
- fi
- if [ ! -f "$server_list" ]
- then
- echo -e "File \"$server_list\" not exist!"
- exit 1
- fi
- # The result directory
- res_dir="result"
- if ! [ -d $res_dir ]
- then
- mkdir $res_dir
- fi
- readonly MAX_THREAD=300 ;# The max number of the sub threads can be forked
- readonly OLD_IFS=${IFS} ;# Save the current IFS
- IFS=$'\n' ;# Set the IFS to '\n"
- usr="ssh_user"
- port=22
- read -sp "Input the password for $usr: " psw
- echo "\nGo!\n"
- (( i = 0 ))
- for line in `cat $server_list`
- do
- if [ -z "$line" ]
- then
- continue
- fi
- echo "$line" | grep '^#' > /dev/null
- if [ $? = 0 ]
- then
- continue
- fi
- ip=`echo $line | awk '{print $1}'`
- id=`echo $line | awk '{print $3}'`
if [ "$ip" == "" ]
then
continue
fi
./remote_exec.exp $usr $ip $port $psw $cmd >> "$res_dir/${id}.txt" &
# If the sub thread numbers upto the MAX_THREAD, then wait for all done
if (( ++i % $MAX_THREAD == 0 ))
then
echo "wait....."
wait
fi
echo -ne "\rProcessing $i."
done
IFS=${OLD_IFS}
wait
echo "Total $i done."
2. 主 expect 调用脚本 remote_exec.exp
- #!/usr/bin/expect
- # remote_exec.exp
- # 作者:亚丹
- # 时间:2009-05-27
- # seesea2517#gmail*com
- # http://seesea.blog.chinaunix.net
- # http://blog.csdn.net/nicenight
- #
- # 功能:实现无交互远程操作
- source func.exp
- if {$argc < 5 } {
- puts "remote_exec needs 5 parameters."
- exit 1
- }
- log_user 0
- log_file log.txt
- set in_user [lindex $argv 0]
- set in_ip [lindex $argv 1]
- set in_port [lindex $argv 2]
- set in_psw [lindex $argv 3]
- set in_cmd [lindex $argv 4]
- set out_res ""
- set ret [remote_exec $in_user $in_ip $in_port $in_psw $in_cmd out_res]
- if {$ret < 0} {
- puts "remote_exec failed (return code: $ret, return str: $out_res)."
- exit 1
- }
- puts $out_res
3. expect 的函数库文件:func.exp,现在看来,也没有再新加过函数……不过这个远大蓝图还是曾经存在过的哈
- #!/usr/bin/expect
- # func.exp
- # 作者:亚丹
- # 时间:2009-05-27
- # seesea2517#gmail*com
- # http://seesea.blog.chinaunix.net
- # http://blog.csdn.net/nicenight
- #
- # 功能:基本函数库文件
- # -----------------------------------
- # Function:
- # Execute the command on the host in_ip
- #
- # Return:
- # If successfully executed, return 0
- # otherwise return the error code:
- # -1: Connect timeout
- # -2: Wrong password
- # -3: Wrong password
- # -4: Checking password timeout
- #
- # Input args:
- # in_user: Specifys the user to login
- # in_ip : Specifys the host for user to login
- # in_psw : Specifys the password for user to login to the host
- # in_cmd : Specifys the command(s) to execute
- #
- # Output args:
- # out_res: Returns the result if executed successfully
- # returns the error description if unsuccessful
- # -----------------------------------
- proc remote_exec {in_user in_ip in_port in_psw in_cmd out_res} {
- upvar $out_res response
- # The for loop is used to do the login action
- set timeout 9999
- for {set i 1} {$i < 3} {incr i} {
- # Last "////" is used as an end symbol
- # spawn -noecho ssh $in_user@$in_ip ls -ogt --time-style=+'%Y%m%d%H%M%S' | grep ^- && echo ////
- spawn -noecho ssh $in_user@$in_ip -p $in_port $in_cmd && echo ////
- expect {
- -nocase "Password:"
- {
- send "$in_psw\n"
- break
- }
- -nocase "(yes/no)"
- {
- send "yes\n"
- continue
- }
- timeout
- {
- set response "Can't connect to host $in_ip\n"
- return -1
- }
- }
- sleep 1
- }
- expect {
- -nocase "password:"
- {
- set response "Wrong password inputed for $in_user@$in_ip.\n"
- return -2
- }
- -nocase "denied"
- {
- set response "Wrong password inputed for $in_user@$in_ip.\n"
- return -3
- }
- timeout
- {
- set response "Timeout while checking password for $in_user@$in_ip.\n"
- return -4
- }
- -re ".*////"
- {
- set response $expect_out(0,string)
- set response [string trim $response "\r\n /"]
- return 0
- }
- }
- }
--------------------------------------------------------------------------------------
对于常用的 scp 操作,有对上述脚本做了针对性的调整,以更加方便的使用:
1. 主脚本 batch_scp.sh
- #!/bin/bash
- # batch_scp.sh
- # 作者:亚丹
- # 时间:2009-05-27
- # seesea2517#gmail*com
- # http://seesea.blog.chinaunix.net
- # http://blog.csdn.net/nicenight
- #
- # 功能:批量无交互scp操作
- #
- # 配置文件格式:
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- # IP xxxx ID/Name
- # para1 is the server list file
- server_list=$1
- if [ -z "$server_list" ]
- then
- echo "Usage: $0 server_list remote_dir local_dir"
- exit 1
- fi
- # If server list file not exists, then exit
- if [ ! -f "$server_list" ]
- then
- echo -e "File \"$server_list\" not exist!"
- exit 1
- fi
- # para2 is the remote directory for scp
- # if not inputed, then set to "/"
- rdir=$2
- if [ -z "$rdir" ]
- then
- rdir="/"
- fi
- # para3 is the local directory for scp
- # if not inputed, then set to "./"
- ldir=$3
- if [ -z "$ldir" ]
- then
- ldir="./"
- fi
- # The result directory
- res_dir="result"
- if ! [ -d $res_dir ]
- then
- mkdir $res_dir
- fi
- readonly MAX_THREAD=2 ;# The max number of the sub threads can be forked
- readonly OLD_IFS=${IFS} ;# Save the current IFS
- IFS=$'\n' ;# Set the IFS to '\n"
- usr="ssh_user"
- port=22
- read -sp "Input the password for $usr: " psw
- (( i = 0 ))
- for line in `cat $server_list`
- do
- if [ -z "$line" ]
- then
- continue
- fi
- echo "$line" | grep '^#' > /dev/null
- if [ $? = 0 ]
- then
- continue
- fi
- ip=`echo $line | awk '{print $1}'`
- id=`echo $line | awk '{print $3}'`
- if [ "$ip" == "" ]
then
continue
fi
# ./remote_exec.exp $usr $ip $port $psw $rdir $ldir >> "$res_dir/${id}.txt" &
# make a local sub-dir for scp, use the id info
lsub_dir="$ldir/${id}"
if [ ! -d "$lsub_dir" ]
then
mkdir "$lsub_dir"
fi
# download and delete the file for release the space of the disk
# (./remote_exec.exp $usr $ip $port $psw $rdir "$lsub_dir" >> "$res_dir/${id}.txt"; sz "$lsub_dir/*"; rm -R "$lsub_dir";) &
# for test, not delete the local sub dir
(./remote_exec.exp $usr $ip $port $psw $rdir "$lsub_dir" >> "$res_dir/${id}.txt"; sz "$lsub_dir/*";) &
# If the sub thread numbers upto the MAX_THREAD, then wait for all done
if (( ++i % $MAX_THREAD == 0 ))
then
echo "wait....."
wait
fi
done
IFS=${OLD_IFS}
wait
echo "Total $i done."
2. remote_exec.exp
- #!/usr/bin/expect
- # remote_exec.exp
- # 作者:亚丹
- # 时间:2009-05-27
- # seesea2517#gmail*com
- # http://seesea.blog.chinaunix.net
- # http://blog.csdn.net/nicenight
- #
- # 功能:实现无交互远程操作
- source func.exp
- if {$argc < 6 } {
- puts "remote_exec needs 6 parameters."
- exit 1
- }
- log_user 0
- log_file log.txt
- set in_user [lindex $argv 0]
- set in_ip [lindex $argv 1]
- set in_port [lindex $argv 2]
- set in_psw [lindex $argv 3]
- set in_rdir [lindex $argv 4]
- set in_ldir [lindex $argv 5]
- set out_res ""
- set ret [remote_exec $in_user $in_ip $in_port $in_psw $in_rdir $in_ldir out_res]
- if {$ret < 0} {
- puts "remote_exec failed (return code: $ret, return str: $out_res)."
- exit 1
- }
- puts $out_res
3. func.exp
- #!/usr/bin/expect
- # func.exp
- # 作者:亚丹
- # 时间:2009-05-27
- # seesea2517#gmail*com
- # http://seesea.blog.chinaunix.net
- # http://blog.csdn.net/nicenight
- #
- # 功能:基本函数库文件
- # -----------------------------------
- # Function:
- # Execute the command on the host in_ip
- #
- # Return:
- # If successfully executed, return 0
- # otherwise return the error code:
- # -1: Connect timeout
- # -2: Wrong password
- # -3: Wrong password
- # -4: Checking password timeout
- #
- # Input args:
- # in_user: Specifys the user to login
- # in_ip : Specifys the host for user to login
- # in_psw : Specifys the password for user to login to the host
- # in_rdir: Specifys the remote directory for scp
- # in_ldir: Specifys the local directory for scp
- #
- # Output args:
- # out_res: Returns the result if executed successfully
- # returns the error description if unsuccessful
- # -----------------------------------
- proc remote_exec {in_user in_ip in_port in_psw in_rdir in_ldir out_res} {
- upvar $out_res response
- # The for loop is used to do the login action
- set timeout 10
- # Last "////" is used as an end symbol
- # spawn -noecho ssh $in_user@$in_ip ls -ogt --time-style=+'%Y%m%d%H%M%S' | grep ^- && echo ////
- spawn -noecho scp -p $in_port $in_user@$in_ip:$in_rdir $in_ldir && echo ////
- expect {
- -nocase "Password:"
- {
- send "$in_psw\n"
- }
- -nocase "(yes/no)"
- {
- send "yes\n"
- exp_continue
- }
- timeout
- {
- set response "Can't connect to host $in_ip\n"
- return -1
- }
- }
- expect {
- -nocase "password:"
- {
- set response "Wrong password inputed for $in_user@$in_ip.\n"
- return -2
- }
- -nocase "denied"
- {
- set response "Wrong password inputed for $in_user@$in_ip.\n"
- send "\003"
- exec kill [exp_pid]
- close
- wait
- return -3
- }
- timeout
- {
- set response "Timeout while checking password for $in_user@$in_ip.\n"
- return -4
- }
- -re "\[^/]+////"
- {
- set response $expect_out(0,string)
- set response [string trim $response "\r\n /"]
- return 0
- }
- }
- }
阅读(4569) | 评论(0) | 转发(4) |