博客 / 詳情

返回

mac終端改造

背景

在windows中,有諸如XShell,SecureCRT等ssh連接神器,但在Mac中,可選擇的工具並不多,ITerm2被一眾程序員吹上了天,但自己實際用下來並不好用,對終端的執念讓我基本上嘗試了所有在Mac上能找得到的終端工具,最終選擇了termius,該工具界面有點極客風,設計簡潔,連接速度快,可惜的是如果用户退出所有記錄將被清除,在被清除兩次後終於無奈的放棄了Mac下唯一上手的終端工具,放棄termius後卻很難再找一個滿意的終端,mac自帶的終端其實還行,就是不大好用,理想中的終端應該滿足以下功能

  • 能夠發送心跳包,不至於因為斷網或者閒置時間過長連接斷開需要重連
  • 能夠有一定的管理功能,記住密碼,不用每次輸入地址和賬號,這個也是最重要的需求
  • 支持tab頁,支持分屏
  • 能夠上傳下載文件
  • 顏值要高
  • 可以選擇複製,因為在終端經常需要複製,大部分終端都可以選擇即可複製,無需手動ctrl+c

如果mac自帶終端能夠滿足以上需求,就完全可以用於日常開發,那麼接下來我們就一步步改造終端

心跳檢測

用過ssh終端的都知道,如果網絡斷開或者長時間不操作,會導致終端掉線,表現為鍵盤無響應,需要重新連接,有時候我們在服務器工作目錄下,重新登錄又要切換到當前目錄,非常到不方便,因此一般終端都可以配置一個心跳檢測,終端會定時發送心跳包保持連接,Mac終端也提供了該配置,編輯文件/etc/ssh/ssh_config增加以下配置

$ sudo vi /etc/ssh/ssh_config

ServerAliveInterval 60
ServerAliveCountMax 999
  • ServerAliveInterval:發送心跳包間隔,單位秒
  • ServerAliveCountMax:最多發送多少次失敗就斷開連接

另外/etc/ssh/ssh_config文件中有SendEnv LANG LC_*配置,將服務器語言環境設置為和本地一樣的環境,一般我們本機是中文環境,但不一定所有Linux服務器都支持中文環境,有時候可能出現亂碼,因此這裏建議註釋掉該配置。

顏值

顏值真的就仁者見仁,mac終端提供了自定義主題的功能,在菜單終端->偏好設置

另外可以編輯文件/etc/motd文件,自定義終端歡迎頁

你可以也可以安裝第三方shell,比如Oh My Zsh

管理功能

這個需求是硬需求,不可能每次連接都重新輸入地址和賬號信息,得有個方案記錄用户名和密碼,並且能夠通過腳本得方式進行自動連接,ssh工具本身處於安全考慮不提供在命令行中指定密碼功能,也就是你不能通過類似ssh {password} {user}@{host}方式進行連接,必須手動輸入密碼,所以第一步就是解決自動登錄問題。

自動登錄

sshpass就是解決ssh手動輸入密碼的問題,你可以通過brew安裝sshpass

brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb

如果沒有安裝brew,你可以下載源碼自行編譯安裝

安裝sshpass後,可以通過以下命令登錄服務器

# 登錄ssh

sshpass -p "password" ssh user@host

# 登錄sftp

sshpass -p "password" sftp user@host

管理

解決了自動登錄問題,那麼就必須有地方管理連接,其實就是把其他終端工具的界面操作搬到控制枱實現,我們假設有一個工具叫PowerTerminal簡稱pw,pw提供以下功能


# 創建新連接

pw create $連接名稱 $ip $用户名 $密碼

# 列出所有連接

pw

# 根據關鍵字搜索連接

pw $關鍵字

# 在顯示所有連接後可以根據編號選擇連接某個連接

# sftp

pw sftp

界面效果

創建連接

$ pw create
➜ 分組    : huaweiyun
➜ ip    : 192.168.10.100
➜ 名稱    : oam
➜ 登錄名: oam
➜ 密碼    : oam
添加主機 192.168.10.100 成功

服務器列表

$ pw

服務器列表
1.  aliyun       ➡  192.168.1.100(hr)
2.  aliyun       ➡  192.168.1.101(bpm)
3.  huaweiyun    ➡  192.168.10.100(oam)
4.  huaweiyun    ➡  192.168.10.101(soa)

➜ 輸入編號    : 

關鍵字搜索

$ pw huawei
服務器列表
1.  huaweiyun    ➡  192.168.10.100(oam)
2.  huaweiyun    ➡  192.168.10.101(soa)

➜ 輸入編號    : 

輸入前面的數字編號後便可自動連接,我希望是打開新的tab頁而不是在當前頁面打開,只要在腳本執行以下命令便可在終端打開新的tab頁並且在新tab頁執行命令

osascript -e 'tell application "Terminal" to activate' -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' -e 'tell application "Terminal" to do script "'"$v_script"'" in selected tab of the front window'

$v_script就是要執行的命令,這裏藉助了Mac自帶的腳本功能,因此無法跨平台,如果是在當前tab頁打開連接就可以直接執行sshpass命令。這裏也要打開腳本輔助功能權限,在系統偏好設置中找到安全與隱私,在輔助功能中將腳本編輯器和終端加進去

完整腳本pw.sh

#!/bin/bash

v_pw_home=~/.pw
v_pw_data=$v_pw_data/data

function help(){
    echo "usage : pw [create|sftp|{searchKey}]"
    echo "           create 根據命令行提示創建連接"
    echo "           sftp 進入sftp模式"
    echo "           searchKey 根據關鍵字進行模糊搜索鏈接支持按照分組名稱,連接名稱,ip進行搜索"
    echo "           help 幫助信息"
}

function init(){
    if [ "$PW_HOME" != "" ]; then
        v_pw_home=$PW_HOME
    fi
    v_pw_data=$v_pw_home/data
    mkdir -p $v_pw_data
}

function login(){
    v_login_host=$1
    v_login_name=$2
    v_login_pwd=$3
    v_action=$4
    printf "\e[0mlogin to ➡ %s with user %s ....\n" $v_login_host $v_login_name
    if [ "$v_login_pwd" != "nil" ]; then
        v_script="sshpass -p '$v_login_pwd' $v_action ${v_login_name}@${v_login_host}"
    else
        v_script="sshpass $v_action ${v_login_name}@${v_login_host}"
    fi
    osascript -e 'tell application "Terminal" to activate' -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' -e 'tell application "Terminal" to do script "'"$v_script"'" in selected tab of the front window'
}

init

cmd=$1


if [ "${cmd}" = "help" ]; then
    help
    exit 0
fi

v_action=ssh
v_spec_number="-1"
if [ "${cmd}" == "create" ]; then
    read -p "➜ 分組    : " v_group
    read -p "➜ ip    : " v_host
    read -p "➜ 名稱    : " v_name
    read -p "➜ 登錄名: " v_username
    read -p "➜ 密碼    : " v_password
    if [ "$v_host" == "" ]; then
        echo "ip地址不能為空"
        exit 1
    fi
    if [ "$v_name" == "" ]; then
        echo "名稱不能為空"
        exit 1
    fi
    if [ "$v_group" == "" ]; then
        v_group="default"
    fi

    if [ "$v_password" == "" ]; then
        v_password="nil"
    fi
    
    echo ${v_host},${v_username},${v_password} >$v_pw_data/${v_group}#$v_host#${v_name}.kimy
    echo "添加主機 "${v_host}" 成功"
    exit 0
fi
if [ "${cmd}" == "sftp" ]; then
    v_action=sftp
    cmd=$2
fi

if [ "${cmd}" == "delete" ]; then
    v_action=delete
    cmd=$2
fi

v_search_key="*.kimy"
v_machine_id=-1

if [ "$cmd" != "" ]; then
    if [ -n "$cmd" ] && [ "$cmd" -eq "$cmd" ] 2>/dev/null; then
        v_machine_id=$cmd
    else
        v_search_key="*${cmd}*.kimy"
    fi
fi

if [ "$v_machine_id" == "-1" ]; then
    v_sequence=1
    printf "服務器列表\n"
    for f in $(find $v_pw_data -name ${v_search_key}|sort)
    do
        v_file_name=$(basename ${f})
        v_names=(${v_file_name//#/ })
        v_group=''
        v_host=''
        v_nick=''
        v_index=1
        for i in ${v_names[@]}  
        do
            if [ "$v_index" == "1" ]; then
                v_group=$i
            fi 
            if [ "$v_index" == "2" ]; then
                v_host=$i
            fi
            if [ "$v_index" == "3" ]; then
                v_nick=(${i//.kimy/})
            fi
            v_index=`expr $v_index + 1`
        done
        printf "\e[0m%-4s" $v_sequence"."
        printf "\e[32m%-12s" $v_group
        printf "\e[0m ➡  \e[35m%s(%s)\n\e[0m" $v_host $v_nick
        v_sequence=`expr $v_sequence + 1`
    done
    
    if [ "$v_sequence" != "2" ]; then
        printf "\n"
    
        read -p "➜ 輸入編號    : " v_machine_id
    else
        v_machine_id="1"
    fi
fi

v_sequence=1
for f in $(find $v_pw_data -name $v_search_key|sort)
do
    if [ "$v_machine_id" == "$v_sequence" ]; then
        v_content=`cat ${f}`
        v_sps=(${v_content//,/ })
        v_host=''
        v_name=''
        v_password=''
        v_index=1
        for i in ${v_sps[@]}  
        do
            if [ "$v_index" == "1" ]; then
                v_host=$i
            fi 
            if [ "$v_index" == "2" ]; then
                v_name=$i
            fi
            if [ "$v_index" == "3" ]; then
                v_password=$i
            fi
            v_index=`expr $v_index + 1`
        done

        if [ "$v_action" == "delete" ];then
            printf "delete file %s\n" $f
            rm -rf "$f"
        else
            login $v_host $v_name $v_password $v_action
        fi
    fi
    v_sequence=`expr $v_sequence + 1`
done

腳本安裝

將腳本保存到本地,比如/you/path/pwoerterminal/pw.sh,在~/.bash_profile加入以下內容


alias pw='/you/path/pwoerterminal/pw.sh'
alias pwf='/you/path/pwoerterminal/pw.sh sftp'
PW_HOME=/you/path/pwoerterminal/data
export PW_HOME
  • pw定義pw命令方便調用,這樣你就可以在任何地方執行pw進入腳本
  • pwf定義sftp命令方便調用,這樣你就可以輸入pwf進入sftp模式
  • PW_HOME:保存數據的地方

修改後執行~/.bash_profile令其生效

效果

其他問題

  • 選擇複製功能目前是無法實現,貌似需要藉助插件,這裏就不折騰了
  • 這裏密碼是明文保存,有一定的安全性問題
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.