Этот метод переносим на любую систему 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 в качестве их интерактивной оболочки.