如何 cd 到另一个屏幕窗口的目录?

如何 cd 到另一个屏幕窗口的目录?

gnome-terminal 有一个很棒的功能,打开新选项卡或窗口时会启动新的 shell,其 cwd = 先前聚焦窗口的 cwd。

我通常在 gnome-terminal 选项卡之一中运行 GNU screen。部分是为了回滚,部分是为了紧凑且枚举显示 5 到 10 个窗口,部分是为了快速按键切换到特定选项卡或上一个选项卡。

但我开始希望能够从一个窗口 cd 到另一个窗口的 CWD。问题是,怎么做?

(顺便问一下,stackexchange 问答是分享我想到的一个简洁的别名、shell 函数或类似 hack 的合适方式吗?我没有阻止,并且我认为 twitter 或 facebook 不是好的选择。)

答案1

此方法可移植到任何 Unix 系统,但依赖于 GNU bash 的功能cd -P才能使其不那么丑陋。

将此(或下面的其他版本,保留逻辑目录)放入您的~/.bashrc(或.zshrc或其他)中,以便它可以在每个交互式 shell (屏幕内外)上运行:

CDS_PREFIX="/var/run/screen/S-$USER"  # screen uses this already
#CDS_PREFIX="/dev/shm/screen-$USER" # if /var/run isn't on tmpfs
# $STY = a string unique to the screen session
if [[ $STY ]]; then
        CDS_DIR="$CDS_PREFIX/dirs.$STY"
        unset CDS_PREFIX

        [[ -d $CDS_DIR ]] || mkdir -m 700 -p "$CDS_DIR"

        # old cmd-every-prompt design: avoids breakage if you run interactive bash from bash, then exit
        # Also, use this on systems without a /proc/<pid>/cwd
        #PROMPT_COMMAND='[[ $WINDOW ]] && ln -sf "$PWD" "$CDS_DIR/$WINDOW"'

        ln -sTf "/proc/$$/cwd" "$CDS_DIR/$WINDOW"       # -T saves a stat call
        cds() { cd -P "$CDS_DIR/$@"; }
else
        # CDS_DIR=( "$CDS_PREFIX"/dirs.* )  # cds will use the first array element
        cds() { cd -P "$CDS_PREFIX/"dirs.*/"$@"; }  # even support shells started before screen.  cd with multiple args takes the first one without complaint.
fi

因此,您可以打开一个新的屏幕窗口,cds 5并将带您进入窗口 5 中的 shell 的 cwd。

这甚至适用于在屏幕外部启动的 shell,甚至在您的屏幕会话存在之前。(因为在那种情况下,glob 扩展发生在运行时cds,而不是在定义它时,就像我注释掉的数组变量 hack 那样,因为它在各方面都更糟糕。)

总开销:

  • 在每个交互式 shell 启动时:
    • 需要解析 8 行非注释代码。
    • 统计数据
    • a ln -sTf 到 tmpfs 上的目录
  • shell 启动后持续的内存开销:
    • 1 个 shell 变量和 1 个小函数
    • 没有环境变量
  • 贮存:
    • 每个屏幕窗口一个符号链接的目录(窗口关闭后不会被删除)
  • 每个命令:
    • 没有任何

如果没有cd -P,那么\w您中的$PS1将会扩展为/proc/3069/cwd,而不是使用 获得的规范(跟随符号链接)路径-P

使用 PROMPT_COMMAND 的版本可以修改cds()为 cd 以将您带到逻辑目录。(将 CWD 作为文本存储在文件中,而不是符号链接中。 pwd > "$CDS_DIR/$WINDOW"只是一个 shell 内置命令,因此比 fork/执行二进制文件的开销要小。还省去了在某些非 Linux 系统上解决 GNU 缺失问题的麻烦readlink。)如果您经常在目录的符号链接中工作,这将很有用,其中pwd -P(和/bin/pwd) 与 不同pwd

您可以使用更新符号链接的函数覆盖cdpushdpopd内置函数,而不是在每个提示符下都执行此操作。 使用此设置,交互式使用 之类的操作(cd foo; command there)将欺骗您的设置,因为cd在子 shell 中运行的 将更新符号链接,但不会修改主 shell 进程的密码。

好的,这是“其他版本”,它挂钩cd、、pushdpopd,并将带您进入与任何屏幕窗口中的 shell 相同的逻辑目录:

# Use this version on systems without `/proc/<pid>/cwd`, or for logical directories (non-dereferencing of symlinks).

CDS_PREFIX="/var/run/screen/S-$USER"
#CDS_PREFIX="/dev/shm/screen-$USER"
if [[ $STY ]]; then
    CDS_DIR="$CDS_PREFIX/dirs.$STY"
    unset CDS_PREFIX
    [[ -d $CDS_DIR ]] || mkdir -m 700 -p "$CDS_DIR"

    function cd    () { command cd    "$@"; pwd > "$CDS_DIR/$WINDOW"; }
    function pushd () { command pushd "$@"; pwd > "$CDS_DIR/$WINDOW"; }
    function popd  () { command popd  "$@"; pwd > "$CDS_DIR/$WINDOW"; }
    #PROMPT_COMMAND='[[ $WINDOW ]] && pwd > "$CDS_DIR/$WINDOW"'
    if [[ -e "$CDS_DIR/$WINDOW" && ! -f "$CDS_DIR/$WINDOW" ]]; then
        rm -f "$CDS_DIR/$WINDOW"  # could exist if switching from symlink-to-dir style
    fi
    cd .

#   cds() { local d="$(<"$CDS_DIR/$1")"; shift; cd "$d" "$@"; }
    cds() { cd "$(<"$CDS_DIR/$1")"; }
else
    # CDS_DIR=( "$CDS_PREFIX"/dirs.* )  # cds will use the first array element
    cds() { cd "$(<"$CDS_PREFIX/"dirs.*/"$1")"; }  # even support shells started before screen.
fi

开销:每个 、 和您输入或粘贴的 tmpfs 都有一个和。否则open(2)相同。首先,在任何功能足够强大的系统上运行和时,这仍然不会造成伤害。 :)write(2)cdpushdpopdbashscreen

归功于https://superuser.com/a/54161/20798对于挂钩 cd 的想法。我非常喜欢这个,比 好多了PROMPT_COMMAND。在查看是否有其他人发明了这一点时发现了这一点,以及我是否应该在这里或 上发布https://unix.stackexchange.com/

我使用了一些 bash-isms(例如[[ ]]),因为我认为 zsh 也支持它们,并且希望没有人使用 POSIX sh 作为他们的交互式 shell。

相关内容