Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1021643
  • 博文数量: 361
  • 博客积分: 25
  • 博客等级: 民兵
  • 技术积分: 1759
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-22 23:18
个人简介

学海无涯 个人blog lnmps.com 新站

文章分类

全部博文(361)

文章存档

2017年(1)

2015年(2)

2014年(55)

2013年(303)

分类: LINUX

2013-04-25 14:38:55

原文地址: 批量无交互远程SSH操作 作者:atomix2

前言
为了参与的这个讨论,整理一下以前写的脚本。现在看来,这个脚本写的很简陋,并发操作也只是分批的控制而不是完全的并行,不过工作起来还算简单稳定。

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

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

1. 主脚本:batch_ssh.sh

  1. #!/bin/bash
  2. # batch_scp.sh
  3. # 作者:亚丹
  4. # 时间:2009-05-27
  5. # seesea2517#gmail*com
  6. # http://seesea.blog.chinaunix.net
  7. # http://blog.csdn.net/nicenight
  8. #
  9. # 功能:批量无交互scp操作
  10. #
  11. # 配置文件格式:
  12. # IP xxxx ID/Name
  13. # IP xxxx ID/Name
  14. # IP xxxx ID/Name
  15. # IP xxxx ID/Name
  16. # IP xxxx ID/Name

  17. server_list=$1
  18. cmd=$2
  19. if [ -z "$server_list" ] || [ -z "$cmd" ]
  20. then
  21.     echo "Usage: $0 server_list command"
  22.     exit 1
  23. fi

  24. if [ ! -f "$server_list" ]
  25. then
  26.     echo -e "File \"$server_list\" not exist!"
  27.     exit 1
  28. fi

  29. # The result directory
  30. res_dir="result"
  31. if ! [ -d $res_dir ]
  32. then
  33.     mkdir $res_dir
  34. fi

  35. readonly MAX_THREAD=300 ;# The max number of the sub threads can be forked
  36. readonly OLD_IFS=${IFS} ;# Save the current IFS
  37. IFS=$'\n' ;# Set the IFS to '\n"

  38. usr="ssh_user"
  39. port=22
  40. read -sp "Input the password for $usr: " psw

  41. echo "\nGo!\n"

  42. (( i = 0 ))

  43. for line in `cat $server_list`
  44. do
  45.     if [ -z "$line" ]
  46.     then
  47.         continue
  48.     fi

  49.     echo "$line" | grep '^#' > /dev/null
  50.     if [ $? = 0 ]
  51.     then
  52.         continue
  53.     fi

  54.     ip=`echo $line | awk '{print $1}'`
  55.     id=`echo $line | awk '{print $3}'`

  56.     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

  1. #!/usr/bin/expect
  2. # remote_exec.exp
  3. # 作者:亚丹
  4. # 时间:2009-05-27
  5. # seesea2517#gmail*com
  6. # http://seesea.blog.chinaunix.net
  7. # http://blog.csdn.net/nicenight
  8. #
  9. # 功能:实现无交互远程操作

  10. source func.exp

  11. if {$argc < 5 } {
  12.     puts "remote_exec needs 5 parameters."
  13.     exit 1
  14. }

  15. log_user 0
  16. log_file log.txt

  17. set in_user [lindex $argv 0]
  18. set in_ip [lindex $argv 1]
  19. set in_port [lindex $argv 2]
  20. set in_psw [lindex $argv 3]
  21. set in_cmd [lindex $argv 4]

  22. set out_res ""

  23. set ret [remote_exec $in_user $in_ip $in_port $in_psw $in_cmd out_res]
  24. if {$ret < 0} {
  25.     puts "remote_exec failed (return code: $ret, return str: $out_res)."
  26.     exit 1
  27. }

  28. puts $out_res

3. expect 的函数库文件:func.exp,现在看来,也没有再新加过函数……不过这个远大蓝图还是曾经存在过的哈

  1. #!/usr/bin/expect
  2. # func.exp
  3. # 作者:亚丹
  4. # 时间:2009-05-27
  5. # seesea2517#gmail*com
  6. # http://seesea.blog.chinaunix.net
  7. # http://blog.csdn.net/nicenight
  8. #
  9. # 功能:基本函数库文件

  10. # -----------------------------------
  11. # Function:
  12. # Execute the command on the host in_ip
  13. #
  14. # Return:
  15. # If successfully executed, return 0
  16. # otherwise return the error code:
  17. # -1: Connect timeout
  18. # -2: Wrong password
  19. # -3: Wrong password
  20. # -4: Checking password timeout
  21. #
  22. # Input args:
  23. # in_user: Specifys the user to login
  24. # in_ip : Specifys the host for user to login
  25. # in_psw : Specifys the password for user to login to the host
  26. # in_cmd : Specifys the command(s) to execute
  27. #
  28. # Output args:
  29. # out_res: Returns the result if executed successfully
  30. # returns the error description if unsuccessful
  31. # -----------------------------------
  32. proc remote_exec {in_user in_ip in_port in_psw in_cmd out_res} {
  33.     upvar $out_res response

  34.     # The for loop is used to do the login action
  35.     set timeout 9999
  36.     for {set i 1} {$i < 3} {incr i} {

  37.         # Last "////" is used as an end symbol
  38.         # spawn -noecho ssh $in_user@$in_ip ls -ogt --time-style=+'%Y%m%d%H%M%S' | grep ^- && echo ////
  39.         spawn -noecho ssh $in_user@$in_ip -p $in_port $in_cmd && echo ////

  40.         expect {
  41.             -nocase "Password:"
  42.             {
  43.                 send "$in_psw\n"
  44.                 break
  45.             }

  46.             -nocase "(yes/no)"
  47.             {
  48.                 send "yes\n"
  49.                 continue
  50.             }

  51.             timeout
  52.             {
  53.                 set response "Can't connect to host $in_ip\n"
  54.                 return -1
  55.             }
  56.         }
  57.     sleep 1
  58.     }

  59.     expect {
  60.         -nocase "password:"
  61.         {
  62.             set response "Wrong password inputed for $in_user@$in_ip.\n"
  63.             return -2
  64.         }

  65.         -nocase "denied"
  66.         {
  67.             set response "Wrong password inputed for $in_user@$in_ip.\n"
  68.             return -3
  69.         }

  70.         timeout
  71.         {
  72.             set response "Timeout while checking password for $in_user@$in_ip.\n"
  73.             return -4
  74.         }

  75.         -re ".*////"
  76.         {
  77.             set response $expect_out(0,string)
  78.             set response [string trim $response "\r\n /"]
  79.             return 0
  80.         }
  81.     }
  82. }
--------------------------------------------------------------------------------------
对于常用的 scp 操作,有对上述脚本做了针对性的调整,以更加方便的使用:
1. 主脚本 batch_scp.sh

  1. #!/bin/bash
  2. # batch_scp.sh
  3. # 作者:亚丹
  4. # 时间:2009-05-27
  5. # seesea2517#gmail*com
  6. # http://seesea.blog.chinaunix.net
  7. # http://blog.csdn.net/nicenight
  8. #
  9. # 功能:批量无交互scp操作
  10. #
  11. # 配置文件格式:
  12. # IP xxxx ID/Name
  13. # IP xxxx ID/Name
  14. # IP xxxx ID/Name
  15. # IP xxxx ID/Name
  16. # IP xxxx ID/Name

  17. # para1 is the server list file
  18. server_list=$1
  19. if [ -z "$server_list" ]
  20. then
  21.     echo "Usage: $0 server_list remote_dir local_dir"
  22.     exit 1
  23. fi

  24. # If server list file not exists, then exit
  25. if [ ! -f "$server_list" ]
  26. then
  27.     echo -e "File \"$server_list\" not exist!"
  28.     exit 1
  29. fi

  30. # para2 is the remote directory for scp
  31. # if not inputed, then set to "/"
  32. rdir=$2
  33. if [ -z "$rdir" ]
  34. then
  35.     rdir="/"
  36. fi

  37. # para3 is the local directory for scp
  38. # if not inputed, then set to "./"
  39. ldir=$3
  40. if [ -z "$ldir" ]
  41. then
  42.     ldir="./"
  43. fi

  44. # The result directory
  45. res_dir="result"
  46. if ! [ -d $res_dir ]
  47. then
  48.     mkdir $res_dir
  49. fi

  50. readonly MAX_THREAD=2 ;# The max number of the sub threads can be forked
  51. readonly OLD_IFS=${IFS} ;# Save the current IFS
  52. IFS=$'\n' ;# Set the IFS to '\n"

  53. usr="ssh_user"
  54. port=22
  55. read -sp "Input the password for $usr: " psw

  56. (( i = 0 ))

  57. for line in `cat $server_list`
  58. do
  59.     if [ -z "$line" ]
  60.     then
  61.         continue
  62.     fi

  63.     echo "$line" | grep '^#' > /dev/null
  64.     if [ $? = 0 ]
  65.     then
  66.         continue
  67.     fi

  68.     ip=`echo $line | awk '{print $1}'`
  69.     id=`echo $line | awk '{print $3}'`
  70.    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

  1. #!/usr/bin/expect
  2. # remote_exec.exp
  3. # 作者:亚丹
  4. # 时间:2009-05-27
  5. # seesea2517#gmail*com
  6. # http://seesea.blog.chinaunix.net
  7. # http://blog.csdn.net/nicenight
  8. #
  9. # 功能:实现无交互远程操作

  10. source func.exp

  11. if {$argc < 6 } {
  12.     puts "remote_exec needs 6 parameters."
  13.     exit 1
  14. }

  15. log_user 0
  16. log_file log.txt

  17. set in_user [lindex $argv 0]
  18. set in_ip [lindex $argv 1]
  19. set in_port [lindex $argv 2]
  20. set in_psw [lindex $argv 3]
  21. set in_rdir [lindex $argv 4]
  22. set in_ldir [lindex $argv 5]

  23. set out_res ""

  24. set ret [remote_exec $in_user $in_ip $in_port $in_psw $in_rdir $in_ldir out_res]
  25. if {$ret < 0} {
  26.     puts "remote_exec failed (return code: $ret, return str: $out_res)."
  27.     exit 1
  28. }

  29. puts $out_res

3. func.exp

  1. #!/usr/bin/expect
  2. # func.exp
  3. # 作者:亚丹
  4. # 时间:2009-05-27
  5. # seesea2517#gmail*com
  6. # http://seesea.blog.chinaunix.net
  7. # http://blog.csdn.net/nicenight
  8. #
  9. # 功能:基本函数库文件

  10. # -----------------------------------
  11. # Function:
  12. # Execute the command on the host in_ip
  13. #
  14. # Return:
  15. # If successfully executed, return 0
  16. # otherwise return the error code:
  17. # -1: Connect timeout
  18. # -2: Wrong password
  19. # -3: Wrong password
  20. # -4: Checking password timeout
  21. #
  22. # Input args:
  23. # in_user: Specifys the user to login
  24. # in_ip : Specifys the host for user to login
  25. # in_psw : Specifys the password for user to login to the host
  26. # in_rdir: Specifys the remote directory for scp
  27. # in_ldir: Specifys the local directory for scp
  28. #
  29. # Output args:
  30. # out_res: Returns the result if executed successfully
  31. # returns the error description if unsuccessful
  32. # -----------------------------------
  33. proc remote_exec {in_user in_ip in_port in_psw in_rdir in_ldir out_res} {
  34.     upvar $out_res response

  35.     # The for loop is used to do the login action
  36.     set timeout 10

  37.     # Last "////" is used as an end symbol
  38.     # spawn -noecho ssh $in_user@$in_ip ls -ogt --time-style=+'%Y%m%d%H%M%S' | grep ^- && echo ////
  39.     spawn -noecho scp -p $in_port $in_user@$in_ip:$in_rdir $in_ldir && echo ////

  40.     expect {
  41.         -nocase "Password:"
  42.         {
  43.             send "$in_psw\n"
  44.         }

  45.         -nocase "(yes/no)"
  46.         {
  47.             send "yes\n"
  48.             exp_continue
  49.         }

  50.         timeout
  51.         {
  52.             set response "Can't connect to host $in_ip\n"
  53.             return -1
  54.         }
  55.     }

  56.     expect {
  57.         -nocase "password:"
  58.         {
  59.             set response "Wrong password inputed for $in_user@$in_ip.\n"
  60.             return -2
  61.         }

  62.         -nocase "denied"
  63.         {
  64.             set response "Wrong password inputed for $in_user@$in_ip.\n"
  65.             send "\003"
  66.             exec kill [exp_pid]
  67.             close
  68.             wait
  69.             return -3
  70.         }

  71.         timeout
  72.         {
  73.             set response "Timeout while checking password for $in_user@$in_ip.\n"
  74.             return -4
  75.         }

  76.         -re "\[^/]+////"
  77.         {
  78.             set response $expect_out(0,string)
  79.             set response [string trim $response "\r\n /"]
  80.             return 0
  81.         }
  82.     }
  83. }

阅读(1047) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~