shell开发的主机登录管理脚本


一个shell 开发的小型跳板机,献丑了
笔者的wsl 系统时ubuntu 20

背景

自从微软发布了新一代的 命令行终端工具,windows terminal 加上WSL对linux系统的支持,我就已经对这个工具爱不释手了,WSL可以让我在windows系统主机上,直接操作linux系统,而windows terminal又可以无缝对接WSL,简直完美,最新的WSL2还添加了对docker的支持,更加方便了我平时的工作
其次,xshell 律师函了我们公司,于是公司集体要求卸载xshell,也适用了国产的xshell工具,final shell,功能方面还是挺用心,性能方面,实在是差强人意,就在这时,我接触到了windows terminal, 这款微软开发的良心命令行终端工具,它有很多功能会让你爱不释手收,比如分屏,换主题等等
用它,你的工作页面可以是这样的
在这里插入图片描述
当然,如果你足够大胆,有想象力,你的背景可以美到不可方物
我的terminal 打开是直接进入我的本机WSL的,等于登录了一台linux系统主机,我可以随意 登录到任何网络可达的服务器
当前的问题是
而我还是无法完全抛弃xshell,因为当我基于登录一台主机,需要一遍一遍的敲类型ssh -p 9090 test@172.20.0.100 然后在一遍一遍 很厌綦烦的去敲密码登录主机,有人可能会问,堡垒机不香吗,堡垒机的确是香,但不是每台主机都需要添加到堡垒机里

于是我心生了一个想法,开发一个可以直接管理主机登录的脚本,他可以帮我管理我曾经登录过的主机

设计

  1. 这个脚本要可以记录我曾经登录过的主机,而且,我只要输入一个模糊的关键字,可以帮我检索到那台主机
  2. 如果搜索不到这台主机,那么就调转录入登录信息,如果登录成功,就想主机信息记录下来,方便下次检索登录
  3. 最好还要可以跟xshell里一样,可以分组,备注信息,让我知道这台主机是干嘛的
  4. 如果可以实现方便的拷贝文件,那就最好了,毕竟windows terminal里没有lszrz 这样好用的工具

实现

流程图

在这里插入图片描述

脚本帮助文档

在这里插入图片描述
这里大概讲一下具体实现

第一次执行脚本,会自动生成两个别名 sshh = ‘bash sshh.sh’
和scpp = ‘bash sshh.sh scp’

录入主机

sshh.sh这个脚本 实现了两种录入主机信息的方式

  • 第一种是参数录入
    比如您敲入sshh -f nsk@172.20.52.44 -p 3030 -g web -m "nginx服务器"
    代表您想要录入的主机信息为
	P地址:172.20.52.44 
	用户名:nsk
	ssh端口:3030
	存放的主机组:web
	备注信息:nginx服务器

	这几个参数都有默认值
		-f  如果后面只有一个ip地址,那就默认是root用户
		-p [默认22端口]  
		-g  [默认default组] 
  • 第二种是交互式录入
    直接输入 sshh 52.44,脚本搜索不到52.44这个字符串,就会直接跳入交互式登录模式,安装指示一步一步输入就可以了,这里添加了一些最基本的验证,如果校验不过,会要求你重复输入哦

登录主机

登录主机,炒鸡简单,直接运行脚本,后面跟上你模糊记得的几个ip地址段就可以了
1. 如果搜索到了一个地址,那就直接登录,如果登录成功,那就让您修改这台主机的记录,知道可以正常登录为止
2. 如果搜索不到,请您直接去录入主机信息
3. 如果搜索到多个,那会全部列出来,供您选择

上传下载文件

你是不是经常为类似的操作 scp -P 3030 nsk@172.20.52.44:/tmp/a.tar .而头疼,要输入一大堆参数,有时候参数记错了 比如 是-P还是-p? 还要重新输入一遍,费事费力,心力交瘁
sshh.sh 脚本里的scp选择 为你带来了福音,这个选项继承了搜索机制,只要这台需要传文件的主机的信息被sshh.sh成功记录,那么您只要,输入ip的一部分,然后添加指定的目录,类似于这样scpp 38.19:/tmp/a.tar .
脚本会自动帮你补全命令行缺少的部分,直接完成传输,是不是很棒,而且使用系统和scp命令是一致的,因为,脚本就是封装了scp命令而已

scpp 38.19:/tmp/a.tar  /tmp  #传输172.26.38.19服务器上一个文件至本地
scpp -r /tmp/dir  38.19:/tmp/ #将本地的dir目录传输到目标主机的/tmp目录

操作主机记录

这里的选项一共有四个 info del edit mv 根据字面意思可以理解大概的意思
比如您可以操作
在这里插入图片描述
在这里插入图片描述

列出主机信息

  1. 列出当前已有的主机分组
    在这里插入图片描述
  2. 列出指定分组的主机
    在这里插入图片描述
  3. 列出所有分组主机
    在这里插入图片描述

代码展示

#!/bin/bash
#主机登录管理脚本
#date 20200603
#author nieshkc


echo_color () {  #用法 echo_color faltal “致命信息”

	fatal_color="1;5;41m" #红底带闪烁,致命错误
	error_color="[1;31m"  #红色字体,执行错误信息
	warn_color="[1;33m"   #黄色字体,警号信息
	succ_color="[1;32m"   #绿色字体,执行正确信息
	info_color="[1;36m"   #蓝色自己,提示信息

	case $1 in
	f*) #fatal
	    echo -e "\e[${fatal_color}${date_time} $2\e[0m"
	;;
	e*) #error
	    echo -e "\e${error_color}${date_time} $2\e[0m"
	;;
	w*) #warning
	    echo -e "\e${warn_color}${date_time} $2\e[0m"
	;;
	s*) #success
	    echo -e "\e${succ_color}${date_time} $2\e[0m"
	;;
	i*) #info
	    echo -e "\e${info_color}${date_time} $2\e[0m"
	;;
	esac
}

usage(){
    echo "说明: <args> 为要搜索的关键字,可以为主机ip中的任意关键字,如果搜索到多个,会悉数列出,如果搜索不到,会调到交互至主机信息录入模式
             运行脚本,会自动生成两个别名sshh scpp 别名信息记录在$host_dir/.alias文件中,可手动添加"
    echo_color i  "添加主机"
    echo_color s  '\t sshh  -f  $user@$ip  [-p 端口(默认22)]  [-g 组名(默认default组)]  [-m 备注信息]'
    echo -e "\t or"
    echo_color s "\t sshh <args>(可以交互式添加主机)"
    echo_color i "传文件"
    echo_color s  "\tbash sshh.sh scp <args>:/tmp  ."
    echo -e "\t说明: 操作基本和scp一致,可以用scpp别名操作,只需要写出可以识别主机名称的ip地址片段即可,脚本会自动补齐需要的部分"
    echo -e   "\teg. scpp -r  49.56:/tmp/dir /tmp"
    echo_color i "操作主机信息"
    echo_color s   "\t bash sshh.sh <options> <args>"
    echo -e "  \t options"
    echo -e "\t    info 查看当前主机信息"
    echo -e "\t    del  删除主机信息"
    echo -e "\t    edit 编辑主机信息"
    echo -e "\t    mv   移动主机至别的组,目标组若不存在自动创建"
    echo_color info "输出主机列表"
    echo_color s   "\t bash sshh.sh list [options]"
    echo -e " \t options"
    echo -e "\t"  '  "" 查看当前主机组信息'
    echo -e "\t"   '  all 使用tree列出所有主机'
    echo -e "\t"   '  $group 列出某个组中的所有主机'

    echo "-h|--help  打印帮助信息"
}

check_dir(){
    for i in $@
    do
     [ -d $i ] || mkdir -p $i
    done
}

check_status(){
if [[ $? -ne 0 ]] ;then
        echo_color e  "$1"
        exit 1
    fi
}


check_command(){
    if command -v apt &>/dev/null  ;then
        tool=apt
    else
        tool=yum
    fi
    command -v $1 &> /dev/null
    [[ $? -eq 0 ]] || sudo $tool  install  $1 -y
    check_status "$1 安装失败请自行安装"

}





expect_copy_id(){
    port=${port:-22}
    check_command expect
    sed -i '/${full_host##*@}/d' ~/.ssh/known_hosts
    rm -f ssh-copy-id_id.*
   expect <<EOF
        set timeout 5
        spawn ssh-copy-id  -i ${ssh_key_file}.pub  -p ${port}  ${full_host}

        expect {
        "yes/no" {send "yes\n";exp_continue}
        "password" {send "${passwd}\n";exp_continue}
        "ssh -p" {send "\n"}
        "WARNING" {send "\n"}
        "Permission denied" {send "\n"}
        }
expect eof
EOF
}



save_host_config(){
    check_dir $host_dir/$group
    cat > $host_dir/$group/${full_host##*@} << EOF
describe="${describe}"
group=${group}
full_host=$full_host
port=$port
passwd=$passwd
create_time=$(date +%Y%m%d-%H:%M)
EOF
}

login_host(){
    ssh -o GSSAPIAuthentication=no \
        -o HashKnownHosts=no \
        -o ConnectTimeout=3\
        -o PasswordAuthentication=no \
        -o StrictHostKeyChecking=no\
        -i ${ssh_key_file} \
         ${full_host}  -p $port
    if [[ $? -ne 0 ]];then
    #    path=$(find ~/.sshh -name "*${host##*@}*")  #这个删除逻辑还有问题
    #    rm -f $path
        #get_passwd
        expect_copy_id
        if [ $? -ne 0 ];then
            echo_color info "主机信息不正确,请修改"
            sleep 2
            vim $path
            exit 0
        else
            login_host
        fi
    fi
}

search_host(){
    str=${1##*@}
    scp_code=$2
    path=$(find ${host_dir} -type f  -name "*$str*")
    N=$(find ${host_dir}  -type f -name "*$str*"|wc -l)    #这个选择逻辑也有问题
    if [[ ${N}  -eq 1 ]];then  #如果可以精确匹配,则用来登录
        . ${path}
        #专门为scp函数查找主机使用,scp_code是标志
        if [[ ${scp_code} == "scp_flag" ]];then
            return 0
        fi
        login_host
        exit 0
    elif [[ ${N} -eq 0 ]];then
        #get_passwd
        echo_color warn  "未搜到您的主机,请录入主机信息"
        read_host_info

    else
        echo_color info "您有多个选择\n ${path}"
        exit 0
    fi

}

option_host(){
    val=$1
    str=${2##*@}
    path=$(find ${host_dir}  -type f -name "*$str*")
    N=$(find ${host_dir} -type f -name "*$str*"|wc -l)

    if [[ _$3 != _ ]] ;then
        dest_group=${host_dir}/$3
        check_dir $dest_group
    fi
#根据参数选择动作
    if [[ $val == "info" ]];then
        action=cat
        prompt="您的${path##*/}主机信息是"
    elif [[ $val == "del" ]];then
        action="rm -f"
        prompt="您删除了${path##*/}主机信息"
    elif [[ $val == 'edit' ]];then
        action="vim"
        prompt="您修改了${path##*/}主机信息"
     elif [[ $val == 'mv' ]];then
        action="mv"
        prompt="您将${path##*/}主机移动至 $3 组"
    fi

    if [[ ${N}  -eq 1 ]];then  #如果可以精确匹配,则用来登录
        echo_color info "$prompt"
        $action $path  $dest_group
        #更新group信息
        [[ $? -eq 0 && -n $3 ]] && sed -i "/group=/c\group=$3 " $(find ${host_dir}  -type f -name "*$str*")
        exit 0
    elif [[ ${N} -eq 0 ]];then
        #get_passwd
        echo_color war "没有您要的主机"

    else
        echo_color info "您有多个选择\n $path"
    fi

}
get_args(){
 while getopts 'f:p:g:m:' OPT ;do
    case $OPT in
    f)
        if [[ $OPTARG =~ @ ]];then
            arg_user=${OPTARG%%@*}
            arg_host_ip=${OPTARG##*@}
        else
            arg_user=root
            arg_host_ip=$OPTARG
        fi

    ;;
    p)
        echo "arg_arg_port=${OPTARG}"
        arg_port=${OPTARG}
    ;;
    g)
        echo "arg_group=${OPTARG}"
        arg_group=${OPTARG}
     ;;
     m)
        echo "arg_describe=${OPTARG}"
        arg_describe=${OPTARG}
     ;;
    esac
done
}
get_passwd (){
    while true
    do
        read  -s  -p "输入主机密码: "  passwd
        expect_copy_id
        if [ $? -eq 0 ];then
            save_host_config
            break
        else
            echo_color erro  "主机信息输入有误"
         fi
    done
    login_host
}

init_all_login(){
    search_host $1   #现搜索是否有记录,如果有,直接登录
    read_host_info  #交互式输入主机信息,直到可以正确登录为止
}

#交互式读入要登录主机的信息,直到成功登录为止
read_host_info(){
    while true;do
        while true;do
            read -p "输入主机信息'eg. [root@]1.1.1.1 [22]': "  _full_host _port
            if [[ ${_full_host} =~ @ ]];then
                _user=${_full_host%%@*}
                _host=${_full_host##*@}
                echo $_user  $_host
            else
                _user=root
                _host=${_full_host}
            fi
          #检验ip地址合法性
            if [[ $_host  =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]];then
                full_host=${_user}@${_host}
            else
                echo_color err "ip地址格式不对,重新输入"
                continue
            fi

            #检验端口合法性
            port=${_port:-22}
            if [[ ${port} =~ ^[0-9]{1,5}$  &&  ${port} -le 65535 ]];then
                    break
                else
                    echo err "输入的端口信息有误"
                    continue
            fi
        done
        ##输入主机属组信息,默认在default组
        if  [[ -z ${group} ]] ;then
            read -p "输入当前主机的组别,默认default组: " _group
            group=${_group:-default}
        fi
        #输入备注信息
        if [[ -z ${describe} ]] ;then
        read -p "您可以备注下这台主机用途: " _describe
            describe=${_describe}
        fi
        #输入密码
        read  -s  -p "输入密码:" _passwd
        passwd=${_passwd}
        expect_copy_id
        if [ $? -eq 0 ];then
            save_host_config
            login_host
            exit 0
        else
            continue
        fi
     done


}

init_constants(){ #全局变量声明
    host_dir=~/.sshh
    scp_file_dir=~/Desktop/
    ssh_key_file=~/.ssh/.id_rsa_sshh
    full_host=
    port=
    passwd=
    group=
    describe=

}

mk_workdir(){
    check_dir ${host_dir}/default  ${host_dir}/${group}
}

get_key (){
 #   sed -i '/${host_ip}/d' known_hosts
	if [ ! -f ${ssh_key_file} ];then
		echo "开始生成密钥对文件"
	    check_dir  ~/.ssh
	  	ssh-keygen -q -P "" -t rsa -f ${ssh_key_file}
        cat ~/.ssh/${ssh_key_file}.pub >>/root/.ssh/authorized_keys
    fi
}


init_args(){

    host_ip=${arg_host_ip}
    port=${arg_port:-22}
    user=${arg_user:-root}
    full_host="${user}@${host_ip}"
    group=${arg_group:-default}
    describe=${arg_describe}
}


mk_alias(){
    file_abs_path=$(readlink -f "$0")
    cat >$host_dir/.alise  <<EOF
#ssh-manager generator
alias  sshh="bash ${file_abs_path}"
alias  scpp="bash ${file_abs_path} scp"

EOF
    SHELL=$(grep $(whoami) /etc/passwd)
    rc_file=~/.${SHELL##*/}rc
    if ! $(grep "ssh-manager" ${rc_file} &>/dev/null);then
        cat $host_dir/.alise >> ${rc_file}
    fi
}


scp_file(){
    local host_str url_path  dest_path  scp_command

    #传目录
    if  [[ $@ =~ '-r' ]];then
        if [[ $3 =~ ":" ]];then
        ##从服务器传至当前主机
            search_host  ${3%%:*} scp_flag
            url_path=$full_host:${3##*:}
            dest_path=${4:-${scp_file_dir}}
           a=$(scp -B -r -P ${port}  ${url_path}  ${dest_path} 2>&1)

            if [[ $a  =~ "Host key verification failed" ]];then
                echo_color warn "${full_host##*@}这台主机还未加入管理,请录入信息"
                read_host_info
            else
                echo_color erro "$a"
            fi
        else
        ##从当前主机传至服务器
            search_host  ${4%%:*} scp_flag
            dest_path=$full_host:${4##*:}
            url_path=${3}
           a=$(scp -B -r -P ${port}  ${url_path}  ${dest_path} 2>&1)

            if [[ $a  =~ "Host key verification failed" ]];then
                echo_color warn "${full_host##*@}这台主机还未加入管理,请录入信息"
                read_host_info
            else
                echo_color erro "$a"
            fi
        fi
    else
     #传文件
        if [[ $2 =~ ":" ]];then
        ##从服务器传至当前主机
            search_host  ${2%%:*} scp_flag
            url_path=$full_host:${2##*:}
            dest_path=${3:-${scp_file_dir}}
            scp -B  -P ${port}  ${url_path}  ${dest_path}

            if [[ $a  =~ "Host key verification failed" ]];then
                echo_color warn "${full_host##*@}这台主机还未加入管理,请录入信息"
                read_host_info
            else
                echo_color erro "$a"
            fi
        else
        ##从当前主机传至服务器
            search_host  ${3%%:*} scp_flag
            dest_path=$full_host:${3##*:}
            url_path=${2}
            a=$(scp -B  -P ${port}  ${url_path}  ${dest_path} 2>&1)

            if [[ $a  =~ "Host key verification failed" ]];then
                echo_color warn "${full_host##*@}这台主机还未加入管理,请录入信息"
                read_host_info
            else
                echo_color erro "$a"
            fi
        fi
        ##从当前主机上传至服务器
    fi
}

list_dir(){
    check_command tree
    if [ -z $1 ] ;then
        tree -L 1 ${host_dir}
    elif [ $1 == "all" ];then
        tree ${host_dir}
    else
        tree ${host_dir}/$1
    fi


}
main () {
init_constants
mk_workdir    #创建工作目录
get_key  #生成主机密钥
mk_alias  #生产别名文件


case $* in
-f*)  #走命令行 传参方式登录
    get_args $*  #搜集命令行参数
    init_args #初始化常量函数
    get_passwd
;;
""|-h|--help)
    usage
;;

info*)
    option_host info $2
;;

del*)
    option_host del  $2
;;

edit*)
    option_host edit  $2
;;
mv*) #更换主机的组别,如果目标组存在,就移动过去,没有就创建
    option_host mv  $2  $3
;;
scp*)
    scp_file $@
;;
list*)
    list_dir $2
;;
*)
      init_all_login $1
;;
esac
}

main $*














欢迎大家批评指正

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值