remote_open: ssh终端下一键用本地软件开远程文件(夹)

引子

使用ssh连接服务器,不可避免会有用本地的软件开远程文件的需求,比如查看远程图片,或用本地文本编辑器打开远程文件。

显然,此时得将远程文件传达本地,手段不一而足,scp、sftp、rsycn、sshfs等等。然而,不论哪一种,都需要开着两个窗口,一个是ssh连接服务器的终端,一个是用来敲传文件命令的终端。更麻烦的是,得对着前者的服务器ip、用户名、文件路径,来敲后者的命令。要知道,在本地,我们只需要输入open <file_path(s) or dir_path(s)>就能一键打开文件(夹)。

为了免去上述体力劳动,我实现了remote open工具,可以像在本地用open命令一样,一键打开远程文件(夹)。

源代码:https://github.com/hyliang96/remote_open.git

介绍

功能

ssh连到服务器后,对着远程的终端:

  • 输入opennc <file_path(s) or dir_path(s)>,根据文件后缀本,自动选用地软件,打开远程的文件(夹)
  • 输入 subnc <file_path(s) or dir_path(s)>,用本地sublime,自动打开远程的文件(夹)。(你也可以修改代码,换成你喜欢的文本编辑器)

本脚本自动用sshfs挂载远程目录,无需手动同步文件

依赖

  • 服务器:nc
  • 本地:nc、ssh、sshfs、zsh

原理

  • ssh连接服务器,并用-R参数进行端口转发,以供nc使用
  • 在远程输入opennc <file_path(s) or dir_path(s)>
  • 远程将 [ 【hostname】、【username】、<file_path(s) or dir_path(s)>之绝对路径],由nc发送到本地
  • 本地侦听到收到远程nc所发,按照其要求将<username>@< hostname>:/sshfs挂载到本地
  • 用本地的open打开所目标文件(夹)

实现

远程

目的:远程将 [ 【hostname】、【username】、<file_path(s) or dir_path(s)>之绝对路径],由nc发送到本地

在~/.bashrc (或~/.bashrc 会加载的.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 【远程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 【远程nc端口】  & )   > /dev/null
    fi
}

本地

对sshfs的封装 -- easy_sshfs

创建 ~/remote_open/easy_sshfs.sh

#!/bin/bash

mount_dir=【自己设置一个文件夹,其下专门用来sshfs挂载远程目录】
# --------------------- sshfs --------------------------
# 挂载一个磁盘
fs() # fs host别名 [远端路径, 默认为"."]
{
    if [ "$#" -lt "1" ]; then
        echo "Usage: fs host别名 [远端路径, 默认为'.']"
        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,则关闭之
    else
        umount $localpath >/dev/null 2>&1 # 不输出,但任然验证一遍
    fi

    if [ ! -d $localpath ]; then mkdir $localpath; fi # 若无挂载目录文件夹,则创建之

    sshfs $host:$remotepath $localpath -o volname=$host -o reconnect -o transform_symlinks -o follow_symlinks
    #  -o local
}
# 卸挂载一个磁盘
ufs()  # ufs [[用户名@]host别名 | 用户名@网址 ] (一个或多个)
{
    if [ "$#" -lt "1" ]; then
        echo "Usage: fs [[用户名@]host别名 | 用户名@网址 ] (一个或多个)"
        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
}

自动挂载远程目录并打开文件

创建 ~/remote_open/remote_open.sh

#!/bin/bash
. ~/remote_open/easy_sshfs.sh
debug=0     # 需要debug输出设为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

端口监听

编辑 ~/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

设置.ssh/config,进行端口转发

为使服务器上nc发送消息到本地被监听到,ssh需将【远程nc端口】同【本地nc端口】转发

Host 【hostname】
    HostName 【服务器的外网ip 或 url】
    User 【username】
    # 私钥
    IdentityFile ~/.ssh/id_rsa
    PreferredAuthentications publickey
    # 用于remote open 的端口转发
    RemoteForward 【远程nc端口】 localhost:【本地nc端口】
   # 其他设置...

其中

  • 【hostname】=服务器上执行hostname的输出
  • 【username】=服务器上执行echo $USER的输出
  • 【服务器的外网ip 或 url】=服务器上执行curl ifconfig.me的输出

设端口监听脚本为开机自启

将端口监听脚本~/remote_open/remote_open_listen.sh设置为开机自启、后台运行

mac用户

操作教程详见

  • 在 “自动操作.app”中新建“应用程序”,
  • 在其中选中运行shell脚本,
  • 选择使用zsh
  • 自动操作脚本内容写
( ( 
zsh ~/remote_open/remote_open_listen.sh
) &) > /dev/null 2>&1
  • 保存到 ~/remote_open/remote_open.app

  • 系统偏好设置/用户与群组/登录项,将~/remote_open/remote_open.app选中,并勾选隐藏,设为开机启动项目。

windows用户

请自行查找windows设置开机自动运行脚本的方法


本人原创,转载请注明出处

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343