背景
在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令其生效
效果
其他問題
- 選擇複製功能目前是無法實現,貌似需要藉助插件,這裏就不折騰了
- 這裏密碼是明文保存,有一定的安全性問題