批量无交互远程SSH操作(2012-07-11)

来源:互联网 发布:ieee802.11n的数据速率 编辑:程序博客网 时间:2024/05/22 13:56
前言
为了参与http://bbs.chinaunix.net/thread-3757201-9-1.html的这个讨论,整理一下以前写的脚本。现在看来,这个脚本写的很简陋,并发操作也只是分批的控制而不是完全的并行,不过工作起来还算简单稳定。

概述
此脚本使用 expect 来对需要交互输入用户名和密码等操作进行自动化,并有对于主机提示自动加入信任列表、操作失败记录日志等功能。

正文
这个脚本分三个文件,逐一附录如下:

1. 主脚本:batch_ssh.sh

#!/bin/bash# batch_ssh.sh# 作者:亚丹# 时间:2009-05-27# seesea2517#gmail*com# http://seesea.blog.chinaunix.net# http://blog.csdn.net/nicenight## 功能:批量无交互ssh操作## 配置文件格式:# IP     xxxx    ID/Name# IP     xxxx    ID/Name# IP     xxxx    ID/Name# IP     xxxx    ID/Name# IP     xxxx    ID/Nameserver_list=$1cmd=$2if [ -z "$server_list" ] || [ -z "$cmd" ]then    echo "Usage: $0 server_list command"    exit 1fiif [ ! -f "$server_list" ]then    echo -e "File \"$server_list\" not exist!"    exit 1fi# The result directoryres_dir="result"if ! [ -d $res_dir ]then    mkdir $res_dirfireadonly MAX_THREAD=300   ;# The max number of the sub threads can be forkedreadonly OLD_IFS=${IFS}   ;# Save the current IFSIFS=$'\n'                 ;# Set the IFS to '\n"usr="ssh_user"port=22read -sp "Input the password for $usr: " pswecho "\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."doneIFS=${OLD_IFS}waitecho "Total $i done."

2. 主 expect 调用脚本 remote_exec.exp

#!/usr/bin/expectsource func.expif {$argc < 5 } {    puts "remote_exec needs 5 parameters."    exit 1}log_user 0log_file log.txtset 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 10    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            }        }    }    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 "\[^/]+////"        -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 fileserver_list=$1if [ -z "$server_list" ]then    echo "Usage: $0 server_list remote_dir local_dir"    exit 1fi# If server list file not exists, then exitif [ ! -f "$server_list" ]then    echo -e "File \"$server_list\" not exist!"    exit 1fi# para2 is the remote directory for scp# if not inputed, then set to "/"rdir=$2if [ -z "$rdir" ]then    rdir="/"fi# para3 is the local directory for scp# if not inputed, then set to "./"ldir=$3if [ -z "$ldir" ]then    ldir="./"fi# The result directoryres_dir="result"if ! [ -d $res_dir ]then    mkdir $res_dirfireadonly MAX_THREAD=2     ;# The max number of the sub threads can be forkedreadonly OLD_IFS=${IFS}   ;# Save the current IFSIFS=$'\n'                 ;# Set the IFS to '\n"usr="ssh_user"port=22read -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    fidoneIFS=${OLD_IFS}waitecho "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.expif {$argc < 6 } {    puts "remote_exec needs 6 parameters."    exit 1}log_user 0log_file log.txtset 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        }    }}





原创粉丝点击