纯手撕shell下远程连接工具,解决shell远程窗口无法自适应问题

一,前言

  • mac 下没有找到一款可以和windows 下的xshell相当的远程连接工具
  • 在网上找了很多expect的脚本,代码都写的好烂,而且都没有解决窗口自适应的问题
  • 鉴于此,于是自己手写了一个远程连接工具

二,准备工作

shell 下的编程知识

  • 函数编程
  • 流程控制
  • 字符串截取
  • sed命令
  • grep 命令
  • expect 编程

其中最复杂的就是expect编程

命令 作用 说明
send 发送信息 向进程发送指定的信息
expect 接收信息 命令和send相反,捕获进程返回的信息
spawn 启动新进程 spwan 后的 send与expect 都是和spawn 最新打开的进程进行交互
interact 允许用户交互 停留在登录的服务器中,不退出来

三,案例分享,shell脚本中嵌套expect脚本

效果入下图:



源代码

  • 我使用了两个文件来实现的,一个是服务器的配置文件,一个是shell脚本文件;配置文件主要用来存放服务器的登录信息,shell脚本文件主要用来执行登录命令
🔥 ls
config.txt sl.sh

sl.sh 文件内容如下:

#!/bin/bash
configPath="./config.txt"
# 一级目录
firstMenu=()
# 二级目录
secondMenu=''
# 一级目录菜单行数下标集合
firstMenuLines=()

# 设置一级菜单栏值与下标
setFirstMenu(){
    # 设置一级菜单栏值数组
    menusTmp=$(cat $configPath|grep '>>>>'|sed -n 's/>>>>//pg')
    firstMenu=(${menusTmp})

    # 设置一级菜单栏下标数组
    for tmpMenu in `cat -n $configPath|grep '>>>>'`
    do 
        if [[ ! $tmpMenu =~ '>>>>' ]]
        then
            # 往数组中添加下标
            firstMenuLines[${#firstMenuLines[@]}]=$tmpMenu
        fi
    done
}
setFirstMenu

# 显示一级菜单栏
showFirstMenu(){
    # 显示菜单栏
    echo -e "\033[36m########################### select group ############################\n"
    for(( m=0; m<${#firstMenu[@]}; m++ ))
    do 
        echo -e "\033[32m ${m} ************************ ${firstMenu[m]}"
    done
    echo -e "\n"
}
showFirstMenu

# 设置二级菜单
setSecondMenu(){
    read -p "Enter your num of options: " menuIndex
    # 截取开始位置
    firstIndex=${firstMenuLines[$menuIndex]}

    # 截取结束位置
    # 条件:是否为数组firstMenuLines最后一个元素,是,则取文件最后一行,否:则取下一个下标
    endMenuLinesIndex=$(( ${#firstMenuLines[@]} - 1 ))
    if [ $menuIndex -eq $endMenuLinesIndex ]
    then 
        endIndex=$( cat $configPath | wc -l )
    else 
        endIndex=${firstMenuLines[$menuIndex+1]}
    fi

    # 显示范围
    showScope=$(( $endIndex - $firstIndex ))

    nodeTmp=$( cat $configPath | grep -A  $showScope ${firstMenu[$menuIndex]}|grep 'ip'|sed -n 's/ip=//pg' )
    secondMenu=($nodeTmp)
}
setSecondMenu

# 显示二级菜单
showSecondMenu(){
    clear
    echo -e "\033[36m########################### select services ############################\n"
    for(( n=0; n<${#secondMenu[@]}; n++ ))
    do 
        echo -e "\033[32m   ${n} ************************ ${secondMenu[n]}"
    done
    echo -e "\n"
}
showSecondMenu

# 获取用户登录信息
getUserInfo(){
    read -p "Enter your num of options: " nodeIndex
    ip=${secondMenu[$nodeIndex]}
    userInfoTmp=$( cat $configPath | grep -A 2 $ip )
    userInfo=($userInfoTmp)
    for info in ${userInfo[@]}
    do 
        if [[ $info =~ "ip=" ]]
        then 
            ip=${info#ip=}
        elif [[ $info =~ "name=" ]]
        then 
            name=${info#name=}
        else
            passwd=${info#passwd=}
        fi 
    done 
}
getUserInfo

# 登录服务器
login(){
    expect -c "
        trap {
            set rows [stty rows]
            set cols [stty columns]
            stty rows \$rows columns \$cols < \$spawn_out(slave,name)
        } WINCH

        set timeout 5;
        spawn  ssh -o TCPKeepAlive=yes -o ServerAliveInterval=4 ${name}@${ip} ;
        expect {
            \"*assword\" {send \"${passwd}\r\" }
            \"yes/no\" {send \"yes\r\"; exp_continue }
            \"yinguohai':\" {send \"${passwd}\r\" }
        } ;
        interact;
        "
}
login 

注意点一:
stty rows \$rows columns \$cols < \$spawn_out(slave,name)
stty 中的 $rows , $cols , $spawn_out 前面都需要加 转移符 \ 。 因为 trap~WINCH中的内容是需要expect来解析的,$rows , $cols, $spawn_out 不能在bash中进行解析,否则都是空,无法传入到expect 中去执行了。

2.config.txt 文件内容

>>>>test
    [node1]
        ip=47.52.00.11
        name=root
        passwd=123
>>>>zyc
    [node1]
        ip=47.70.89.12
        name=root
        passwd=123456
    [node2]
        ip=47.222.78.109
        name=root
        passwd=1234
>>>>lc
    [node1]
        ip=47.95.11.49
        name=root
        passwd=Y123455
posted @ 2020-11-12 21:58  大步向前blue  阅读(417)  评论(0编辑  收藏  举报