提示反映 sshfs 挂载点?

提示反映 sshfs 挂载点?

我用来sshfs将远程文件夹远程安装到本地计算机,问题是我需要一种方法来知道我正在本地计算机上的远程文件夹或local文件夹下工作,以避免意外对远程文件夹造成伤害。

如何让 zsh/bash 提示反映我当前处于远程挂载点,以便我会更仔细地执行操作?

示例:现在当我 cd 到 sshfs 时local_of_remote_mountpoint,提示会通知我这是使用sshfs以下方式安装的文件夹:user@host: sshfs% ls

答案1

我们在这里面临两个不同的问题:

  1. 如何知道当前工作目录 (PWD) 是否位于由sshfs;挂载的文件系统上
  2. 如何在 shell 提示符中反映第 1 点。

当前工作目录是由 挂载的文件系统的一部分吗sshfs

将 PWD 与安装点进行比较并不可靠。例如,如果 PWD 的组件是指向安装点的符号链接,则它可能不起作用。

在 GNU/Linux 上,df和等工具findmnt能够确定目录所在的安装点。此外,两者都可以报告FSTYPE文件系统的属性,该属性设置fuse.sshfs为由sshfs.

因此,您可以检查:

# df always prints a header line, we want to skip it
[ "fuse.sshfs" = "$(df --output=fstype . | tail -n +2)" ] && ...

或者:

[ "fuse.sshfs" = "$(findmnt --noheadings --output=FSTYPE --target .)" ] && ...

您可以将此测试包装在脚本中并使其在您的PATH.在这里我们将其称为check_sshfs_mp

#!/bin/sh
[ "fuse.sshfs" = "$(findmnt --noheadings --output=FSTYPE --target .)" ] && exit 0
exit 1

如何根据我们所在的挂载点设置 shell 提示符?

在两者中bashzsh您都可以设置PS1shell 变量,该变量将扩展为主要提示符。

您可以在bash相关函数的包装器中执行此操作:cdpushdpopd(学分:感谢对“Conditional PS1”的回答提醒我cd不是唯一的),将此代码添加到您的~/.bashrc

cd () { builtin cd "$@" && chpwd; }

pushd () { builtin pushd "$@" && chpwd; }

popd () { builtin popd "$@" && chpwd; }

chpwd () {
    normal='\[\e[0m\]'
    red='\[\e[1;31m\]'
    PS1='[\u@\h \W]\$ '
    if command -v check_sshfs_mp > /dev/null 2>&1; then
        check_sshfs_mp && PS1='[\u@\h '"$red"'R'"$normal"' \W]\$ '
    fi
}

chpwd函数调用check_sshfs_mpand ,如果其退出状态为0,则向 添加一个红色R字母PS1。您可能需要根据您的喜好
调整默认值。PS1

它在zsh某种程度上更容易,因为每当当前工作目录更改时都会zsh执行特殊函数(参考文献:Z Shell 手册,chpwd特殊功能)。您可以将提示设置函数添加到与 一起执行的钩子函数数组中chpwd
假设您不使用用户贡献干扰提示设置,您可以将此代码添加到您的~/.zshrc

chpwd_check_sshfs_mp () {
    PS1='%m%# '
    if command -v check_sshfs_mp > /dev/null 2>&1; then
        check_sshfs_mp && PS1='%m %F{red}R%f %# '
    fi
}
chpwd_functions+=( chpwd_check_sshfs_mp )

同样,我们只是在成功R时向主提示添加红色。chech_sshfs_mp

请注意,如果启动终端的 PWD 位于已安装的文件系统上,则包装cd和添加挂钩函数将无法确保提示设置正确。您至少需要 a才能触发正确的提示,这可能会产生误导。chpwd_functionssshfscd

用户对zsh执行提示主题的贡献将需要特别指定自定义提示的解决方案。
您仍然可以使用以下命令关闭提示主题

prompt off

来试验这段代码。


整合评论中提出的要点zsh

如果您喜欢指定提示颜色ANSI 转义序列(而不是颜色名称)您可以将PS1上面代码片段中的赋值行更改为:

check_sshfs_mp && PS1="$(print '%m %{\e[1;31m%}R%{\e[0m%} %# ')"

或者

PS1='%m'"$(check_sshfs_mp && print '%{\e[1;31m%} R %{\e[0m%}')"'%# '

请注意,print需要将\es 转换为实际的转义字符,并且%{...%}需要使用该形式以避免提示代码行为不当。参考资料:zsh常见问题解答:如何在 color xterm 上获得彩色提示?

如果您希望每次设置主提示时都执行检查,则可以避免添加挂钩函数chpwd_functions并将其添加到您的.zshrc

setopt PROMPT_SUBST
export PS1='%m$(check_sshfs_mp && print "%{\e[1;31m%} R %{\e[0m%}")%# '

PROMPT_SUBST需要该选项来启用提示显示中的命令替换。参考:迅速扩张在 Z Shell 手册中。

答案2

按照 @fra.san 的建议,您可以通过调整来修改 LOCAL 提示符,PS1以便它反映路径中的文件夹是使用sshfs.

首先检查您的终端是否支持颜色提示。在 yr~/.kshrc或中包含以下内容~/.bashrc

# Option is turned off by default to not distract the user.
force_color_prompt=yes

if [ -n "$force_color_prompt" ]; then
    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
    # you have color support; assume it's compliant with Ecma-48
    # (ISO/IEC-6429). If support lacks use `setf` rather than `setaf`.
        color_prompt=yes
    else
        color_prompt=""
    fi
fi

接下来,每次使用包装器在本地 FS 上安装远程卷时sshfs_wrp,都会自动将已安装的远程卷的路径附加到临时文件中,例如/tmp/tmp_rem_vol.您可以使用 sshfs 命令的简单包装来执行此操作:

#!/usr/bin/sh
# script name: sshfs_wrp   # wrapper for sshfs
mount_path="$( echo "$@"| cut -d" " -f $# )"  # usually last parameter to `sshfs`
# Note: above will break when parameters passed to sshfs_wrp 
# contain blanks between quotes. 
echo "$mount_path" >> /tmp/tmp_rem_vol
sshfs "$@" 
exit 0

确保脚本可执行并且可以通过 PATH 环境变量访问其位置。

~/.kshrc接下来,在您的或中定义一个函数~/.bashrc来设置标志变量 ,remFlag以防[R]该字符串"$(pwd)"指示您当前在远程卷子树中工作,该子树之前已使用 挂载sshfs_wrp。我用的case是便携性。
编辑: 请注意,一旦在case模式匹配部分找到匹配项,就必须退出 while 循环。

function check_rem_vol () {
    if [ -s /tmp/tmp_rem_vol ] ; then
        while read rem_vol; do
            case "$(pwd)" in 
                # check whether pwd contains sshfs_wrp-mounted volume 
                *"${rem_vol}"*) remFlag="[R]" ; break  ;;  
                *) remFlag="" ;;
            esac
        done < /tmp/tmp_rem_vol
    else
        remFlag=""
    fi
    echo "$remFlag"
}

PS1最后,在 yr~/.kshrc或中修改 yr 提示符~/.bashrc,方法是在提示符中包含远程卷标志 ,rem_vol以亮绿色显示,以防使用 挂载某些远程卷sshfs_wrp

if [ "$color_prompt" = yes ]; then
    # For Debian based systems only
    #PS1="${debian_chroot:+($debian_chroot)}\[\e[0;38;5;166m\][\#/\!]\[\e[1;34m\] \w\[\e[38;5;46m\] \$(check_rem_vol)\[\e[1;38;5;166m\]>\[\e[0m\]"

    # For Archlinux
    PS1="\\[\\e[0;38;5;166m\\][\\#/\\!]\\[\\e[1;34m\\] \\w\\[\\e[38;5;46m\\] \$(check_rem_vol)\\[\\e[1;38;5;166m\\]\\> \\[\\e[0m\\]"
else
    # For Debian based systems only
    #PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
    #PS1="${debian_chroot:+}[\#/\!] \[\w \$(check_rem_vol)\]>"

    # For Archlinux
    PS1="[\\#/\\!] \\[\\w \$(check_rem_vol)\\]>"
fi
export PS1
unset color_prompt force_color_prompt

可以改进该解决方案以减少移动部件的数量并改进临时文件或多个临时文件的创建/tmp/tmp_rem_vol,以防多个 ssh 连接共存并且从不同的远程主机安装远程卷。

这应该适用于Debian 或 Arch Lx 平台上的bash或shell 内的一个 ssh 连接。ksh

卸载远程卷、会话注销或关闭 ssh 连接时,您还应该注意擦除/tmp/tmp_rem_vol以避免持久性问题。您还会发现大量参考资料和技巧来实现自动化。

华泰

相关内容