引子
使用ssh連接服務(wù)器臀晃,不可避免會(huì)有用本地的軟件開遠(yuǎn)程文件的需求觉渴,比如查看遠(yuǎn)程圖片,或用本地文本編輯器打開遠(yuǎn)程文件徽惋。
顯然案淋,此時(shí)得將遠(yuǎn)程文件傳達(dá)本地,手段不一而足险绘,scp踢京、sftp、rsycn宦棺、sshfs等等瓣距。然而,不論哪一種代咸,都需要開著兩個(gè)窗口蹈丸,一個(gè)是ssh連接服務(wù)器的終端,一個(gè)是用來敲傳文件命令的終端呐芥。更麻煩的是逻杖,得對著前者的服務(wù)器ip、用戶名思瘟、文件路徑荸百,來敲后者的命令。要知道滨攻,在本地够话,我們只需要輸入open <file_path(s) or dir_path(s)>
就能一鍵打開文件(夾)。
為了免去上述體力勞動(dòng)铡买,我實(shí)現(xiàn)了remote open
工具,可以像在本地用open
命令一樣霎箍,一鍵打開遠(yuǎn)程文件(夾)奇钞。
源代碼:https://github.com/hyliang96/remote_open.git
介紹
功能
ssh連到服務(wù)器后,對著遠(yuǎn)程的終端:
- 輸入
opennc <file_path(s) or dir_path(s)>
漂坏,根據(jù)文件后綴本景埃,自動(dòng)選用地軟件,打開遠(yuǎn)程的文件(夾) - 輸入
subnc <file_path(s) or dir_path(s)>
顶别,用本地sublime谷徙,自動(dòng)打開遠(yuǎn)程的文件(夾)。(你也可以修改代碼驯绎,換成你喜歡的文本編輯器)
本腳本自動(dòng)用sshfs掛載遠(yuǎn)程目錄完慧,無需手動(dòng)同步文件
依賴
- 服務(wù)器:nc
- 本地:nc、ssh剩失、sshfs屈尼、zsh
原理
-
ssh
連接服務(wù)器册着,并用-R
參數(shù)進(jìn)行端口轉(zhuǎn)發(fā),以供nc
使用 - 在遠(yuǎn)程輸入
opennc <file_path(s) or dir_path(s)>
- 遠(yuǎn)程將 [ 【hostname】脾歧、【username】甲捏、<file_path(s) or dir_path(s)>之絕對路徑],由
nc
發(fā)送到本地 - 本地偵聽到收到遠(yuǎn)程
nc
所發(fā)鞭执,按照其要求將<username>@< hostname>:/
用sshfs
掛載到本地 - 用本地的
open
打開所目標(biāo)文件(夾)
實(shí)現(xiàn)
遠(yuǎn)程
目的:遠(yuǎn)程將 [ 【hostname】司顿、【username】、<file_path(s) or dir_path(s)>之絕對路徑]兄纺,由nc
發(fā)送到本地
在~/.bashrc (或~/.bashrc 會(huì)加載的.bash_aliases大溜、.bash_function)中,添加以下代碼囤热。
subnc(){
dirs=""
for arg in $@; do
if [ -e $arg ]; then
path_arg=$(abspath $arg)
dirs="$dirs; $path_arg"
else
echo not exist: $arg
fi
done
if [ "${dirs:0:2}" = "; " ]; then
dirs=${dirs:2}
fi
if [ "$dirs" != "" ]; then
(echo "sub; $USER; `hostname`; $dirs" | nc localhost 【遠(yuǎn)程nc端口】 & ) > /dev/null
fi
}
opennc(){
dirs=""
for arg in $@; do
if [ -e $arg ]; then
path_arg=$(abspath $arg)
dirs="$dirs; $path_arg"
else
echo not exist: $arg
fi
done
if [ "${dirs:0:2}" = "; " ]; then
dirs=${dirs:2}
fi
if [ "$dirs" != "" ]; then
(echo "open; $USER; `hostname`; $dirs" | nc localhost 【遠(yuǎn)程nc端口】 & ) > /dev/null
fi
}
本地
對sshfs的封裝 -- easy_sshfs
創(chuàng)建 ~/remote_open/easy_sshfs.sh
#!/bin/bash
mount_dir=【自己設(shè)置一個(gè)文件夾猎提,其下專門用來sshfs掛載遠(yuǎn)程目錄】
# --------------------- sshfs --------------------------
# 掛載一個(gè)磁盤
fs() # fs host別名 [遠(yuǎn)端路徑, 默認(rèn)為"."]
{
if [ "$#" -lt "1" ]; then
echo "Usage: fs host別名 [遠(yuǎn)端路徑, 默認(rèn)為'.']"
return
fi
host=$1
if [ "$#" -gt "1" ]; then
remotepath="$2"
else
remotepath="."
fi
localpath="$mountdir/${host}"
if [ "`pgrep -lf sshfs | grep \"$localpath \"`" != "" ]; then
echo $localpath is already mounted, now remount
umount $localpath # 若在mount此localpath,則關(guān)閉之
else
umount $localpath >/dev/null 2>&1 # 不輸出旁蔼,但任然驗(yàn)證一遍
fi
if [ ! -d $localpath ]; then mkdir $localpath; fi # 若無掛載目錄文件夾锨苏,則創(chuàng)建之
sshfs $host:$remotepath $localpath -o volname=$host -o reconnect -o transform_symlinks -o follow_symlinks
# -o local
}
# 卸掛載一個(gè)磁盤
ufs() # ufs [[用戶名@]host別名 | 用戶名@網(wǎng)址 ] (一個(gè)或多個(gè))
{
if [ "$#" -lt "1" ]; then
echo "Usage: fs [[用戶名@]host別名 | 用戶名@網(wǎng)址 ] (一個(gè)或多個(gè))"
return
fi
for host in $@; do
# host=$1
localpath="$mountdir/${host}"
umount $localpath
if [ "`ls -A $localpath`" = "" ]; then
rm $localpath -rf # 若掛載目錄是空文件夾,則刪除之
else
echo original dir $localpath is now recovered
fi
done
}
# 列出目前mount的所有磁盤
fsls()
{
answer=`pgrep -lf sshfs | awk '{print $1 " " $3}'`
if [ "$answer" != "" ]; then echo "pid host_alias:remote_path"; echo $answer; fi
}
# 列出掛載路徑
mtls()
{
ls $mountdir -la
}
自動(dòng)掛載遠(yuǎn)程目錄并打開文件
創(chuàng)建 ~/remote_open/remote_open.sh
#!/bin/bash
. ~/remote_open/easy_sshfs.sh
debug=0 # 需要debug輸出設(shè)為1
string="$1"
args=("${(@s/; /)string}")
[ $debug -ne 0 ] && declare -p args
app=${args[1]}
user=${args[2]}
host_alias=${args[3]}
remote_paths=(${args[@]:3:${#args[@]}})
[ $debug -ne 0 ] && echo app: $app
[ $debug -ne 0 ] && echo user: $user
[ $debug -ne 0 ] && echo host_alias: $host_alias
[ $debug -ne 0 ] && declare -p remote_paths
mounts="$(pgrep -lf sshfs | awk '{print $3}')"
mounts=("${(@s/\\n/)mounts}")
[ $debug -ne 0 ] && echo mounts: $mounts
mount_dir=$mountdir
[ $debug -ne 0 ] && echo mount_dir: $mount_dir
mount_folder=$user@$host_alias
if ! [[ ${mounts} =~ $mount_folder:/ ]] || ! [ -d $mount_dir/$host_alias/home ]; then
[ $debug -ne 0 ] && echo hasnt mounted $mount_folder:/, start mounting
[ $debug -ne 0 ] && echo fs $mount_folder /
fs $mount_folder /
[ $debug -ne 0 ] && echo finished mounting
else
[ $debug -ne 0 ] && echo has mounted $mount_folder:/
fi
folders=()
files=()
for remote_path in ${remote_paths}; do
[ $debug -ne 0 ] && echo remote_path: $remote_path
local_path=$mount_dir/$mount_folder/$remote_path
[ $debug -ne 0 ] && echo local_path: $local_path
if [ -d $local_path ]; then
[ $debug -ne 0 ] && echo local_path is dir
folders+="$local_path"
elif [ -f $local_path ]; then
[ $debug -ne 0 ] && echo local_path is file
files+="$local_path"
else
echo no such file or directory: $local_path
fi
done
[ $debug -ne 0 ] && declare -p folders
[ $debug -ne 0 ] && declare -p files
# 用本地軟件打開棺聊,適用于mac伞租,windows用戶需修改下面代碼
if [ "$app" = "sub" ]; then
# 你也可以修改代碼,換成你喜歡的文本編輯器
open_with="/Applications/Sublime Text.app"
elif [ "$app" = "open" ]; then
open_with=""
fi
if [ "$open_with" = "" ]; then
for folder in $folders; do
# folder=${folder/ /\\ }
[ $debug -ne 0 ] && echo $folder
open $folder
done
if [ $#files -ne 0 ]; then
open $files
fi
else
for folder in $folders; do
# folder=${folder/ /\\ }
[ $debug -ne 0 ] && echo $folder
open -a $open_with $folder
done
if [ $#files -ne 0 ]; then
open -a $open_with $files
fi
fi
端口監(jiān)聽
編輯 ~/remote_open/remote_open_listen.sh
#!/bin/zsh
port=【本地nc端口】
this_dir_abs_path=$(cd "$(dirname "$0")"; pwd)
echo start nc
while read line; do
echo "$line"
zsh $this_dir_abs_path/remote_open.sh $line
done < <(nc -lk $port)
echo end nc
設(shè)置.ssh/config限佩,進(jìn)行端口轉(zhuǎn)發(fā)
為使服務(wù)器上nc發(fā)送消息到本地被監(jiān)聽到葵诈,ssh需將【遠(yuǎn)程nc端口】同【本地nc端口】轉(zhuǎn)發(fā)
Host 【hostname】
HostName 【服務(wù)器的外網(wǎng)ip 或 url】
User 【username】
# 私鑰
IdentityFile ~/.ssh/id_rsa
PreferredAuthentications publickey
# 用于remote open 的端口轉(zhuǎn)發(fā)
RemoteForward 【遠(yuǎn)程nc端口】 localhost:【本地nc端口】
# 其他設(shè)置...
其中
- 【hostname】=服務(wù)器上執(zhí)行
hostname
的輸出 - 【username】=服務(wù)器上執(zhí)行
echo $USER
的輸出 - 【服務(wù)器的外網(wǎng)ip 或 url】=服務(wù)器上執(zhí)行
curl ifconfig.me
的輸出
設(shè)端口監(jiān)聽腳本為開機(jī)自啟
將端口監(jiān)聽腳本~/remote_open/remote_open_listen.sh
設(shè)置為開機(jī)自啟、后臺(tái)運(yùn)行
mac用戶
- 在 “自動(dòng)操作.app”中新建“應(yīng)用程序”祟同,
- 在其中選中運(yùn)行shell腳本作喘,
- 選擇使用zsh
- 自動(dòng)操作腳本內(nèi)容寫
( (
zsh ~/remote_open/remote_open_listen.sh
) &) > /dev/null 2>&1
保存到
~/remote_open/remote_open.app
在
系統(tǒng)偏好設(shè)置/用戶與群組/登錄項(xiàng)
,將~/remote_open/remote_open.app
選中晕城,并勾選隱藏
泞坦,設(shè)為開機(jī)啟動(dòng)項(xiàng)目。
windows用戶
請自行查找windows設(shè)置開機(jī)自動(dòng)運(yùn)行腳本的方法
本人原創(chuàng)砖顷,轉(zhuǎn)載請注明出處