У gnome-терминала есть отличная функция, при которой открытие новой вкладки или окна запускает новую оболочку с помощью cwd = cwd ранее сфокусированного окна.

Я обычно запускаю экран GNU на одной из моих вкладок терминала gnome. Частично для прокрутки, частично для компактного и пронумерованного отображения от 5 до 10 окон, частично для быстрого нажатия клавиш для перехода к определенной или предыдущей вкладке.

Но я начинаю хотеть, чтобы я мог в одном окне перейти к CWD другого окна. Вопрос в том, как?

(Кстати, является ли стек-обмен Q & self-A подходящим способом поделиться аккуратным псевдонимом, функцией оболочки или хаком, подобным этому, который я придумал? У меня нет блока, и я не думаю, что Twitter или Facebook были бы хорошими вариантами.)

1 ответ1

0

Этот метод переносим на любую систему Unix, но зависит от функциональности cd -P GNU bash, чтобы сделать его не уродливым.

Поместите это (или другую версию ниже, которая сохраняет логические каталоги) в ваш ~/.bashrc (или .zshrc или любой другой), чтобы он работал для каждой интерактивной оболочки (внутри и снаружи экрана):

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 перенесет вас в cwd оболочки в окне 5.

Это даже работает для оболочек, запущенных вне экрана, и даже до того, как ваш сеанс экрана существовал. (поскольку в этом случае расширение glob происходит во время выполнения cds , а не тогда, когда оно было определено, как в случае с хаком переменная массива, который я прокомментировал, поскольку он хуже во всех отношениях.)

Всего накладных расходов:

  • при каждом запуске интерактивной оболочки:
    • 8 строк без комментариев кода для разбора.
    • стат
    • ln -sTf в каталог на tmpfs
  • продолжающиеся накладные расходы памяти после запуска оболочки:
    • 1 оболочка var и 1 крошечная функция
    • нет условий
  • место хранения:
    • каталог одной символической ссылки на окно экрана (не удаляется после закрытия окна)
  • по команде:
    • никто

Без cd -P \w в вашем $PS1 расширится до /proc/3069/cwd , а не на канонический (по символическим ссылкам ) путь, который вы получите с -P .

Версия, которая использует PROMPT_COMMAND, может изменить cds cds() на cd, чтобы перенести вас в логический каталог. (Храните CWD в виде текста в файле, а не в символической pwd > "$CDS_DIR/$WINDOW" - это просто встроенная оболочка, поэтому она требует меньше накладных расходов, чем форк / исполняемый двоичный файл. Также избавляет от необходимости обходить отсутствующую readlink GNU в некоторых системах, отличных от Linux.) Это было бы полезно, если вы часто работаете с символическими ссылками на каталоги, где pwd -P/bin/pwd) отличается от pwd .

Вы можете переопределить встроенные функции cd , pushd и popd функциями, которые обновляют символическую ссылку, вместо того, чтобы делать это КАЖДЫЙ запрос. При такой настройке интерактивное использование таких вещей, как (cd foo; command there) обманет вашу настройку, потому что cd который запускается в подоболочке, обновит символическую ссылку, но без изменения pwd основного процесса оболочки.

Хорошо, вот "другая версия", которая перехватывает cd , pushd и popd и перенесет вас в тот же логический каталог, что и ваша оболочка в любом окне экрана:

# 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

Накладные расходы: open(2) и write(2) в tmpfs для каждого cd , pushd и popd вы вводите или вставляете. В остальном тоже самое. Всё равно не повредит, на любой системе, достаточно мощной, чтобы запускать bash и screen в первую очередь. :)

Благодарим https://superuser.com/a/54161/20798 за идею подключения CD. Мне нравится это намного лучше, чем PROMPT_COMMAND . Обнаружил, что пока смотрю, изобрел ли это кто-то еще, и стоит ли мне публиковать здесь или на https://unix.stackexchange.com/ .

Я использовал некоторые bash-isms (например, [[ ]]), потому что я думаю, что zsh также поддерживает их, и, надеюсь, никто не использует POSIX sh в качестве их интерактивной оболочки.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .