Что такое ZSH-эквивалент $ PROMPT_COMMAND BASH?

24

BASH поддерживает $PROMPT_COMMANDпеременную среды, которая определяет команду, выполняемую перед любым интерактивным приглашением первого уровня. Я ищу ZSH-эквивалент этого.

Документация говорит, что есть функция, которую precmdя могу определить для достижения этой цели; однако я понятия не имею, как определить его из переменной среды.

Я рассмотрел передачу переменной среды, которая заставит ZSH прочитать файл, содержащий определение этой функции, но ZSH , похоже, не поддерживает такие вещи : он читает только глобальные файлы, а затем файлы для каждого пользователя. Я могу заменить их, но я не могу добавить к ним без изменения файлов, что я не могу сделать.

Итак, как мне определить хук предварительного запроса в ZSH через переменную окружения, как я бы использовал $PROMPT_COMMANDв BASH?

Shnatsel
источник
По правде говоря, мне нужен хук после выполнения интерактивной команды, но ни одна из оболочек не предоставляет его, поэтому мне приходится прибегать к хукам, предшествующим подсказкам - они кажутся настолько близкими, насколько я могу получить.
Шнацель
1
Хм, мне интересно, в чем разница между постинтерактивным выполнением команд и предварительным приглашением . Помимо концептуальной разницы, где вы наблюдаете на самом деле разницу. (Давайте опустим команды exitи exec, ок ;))
mpy
@mpy есть разница при запуске фонового задания, потому что фоновые задания не зависят от последовательности подсказок.
Шнацель
1
Хорошо, я понял это. Итак, как насчет чего-то подобного: start() { eval "$@"; echo post-command-code }а затем использовать zle-привязку для выполнения командной строки с помощью startprepended?
mpy
1
DEBUGЛовушка хорошая находка, но вы все еще есть проблема , как определить его. Я еще раз расширил свой ответ, но я оставляю вам право написать свой собственный ответ относительно решения ловушки DEBUG. :)
mpy

Ответы:

24

Самый простой подход к эмуляции bash, $PROMPT_COMMANDкоторый приходит мне в голову, - это использовать precmdкрючок, как вы уже поняли. Определите это как

precmd() { eval "$PROMPT_COMMAND" }

и вы можете сделать что-то подобное:

$ PROMPT_COMMAND='echo Hello, it is now $(date)'
Hello, it is now Mon, Mar 31, 2014 7:08:00 PM
$ whoami      
user
Hello, it is now Mon, Mar 31, 2014 7:08:21 PM     
$

Обратите внимание на одинарные кавычки в этом примере, иначе они $(date)будут раскрыты слишком рано, то есть уже при определении, $PROMPT_COMMANDа не при вызове перед приглашением.


Если вы хотите сохранить (и не хотите изменять) существующее определение, вы можете использовать этот подход:

$ prmptcmd() { eval "$PROMPT_COMMAND" }
$ precmd_functions=(prmptcmd)

При этом prmptcmdфункции выполняются после существующей precmd()функции.


Наконец, вот способ, который подходит для использования в программном пакете, который не должен изменять пользовательские или системные файлы и не может вводить команды в интерактивном режиме.

Примером порождения сеанса bash может быть

PROMPT_COMMAND="echo foo" bash

Для появления Zsh вы можете использовать

ZDOTDIR=/program/dir zsh

что приводит /program/dir/.zshrcк источнику. В этом файле precmd()ловушка может быть определена, как описано выше. Если вы хотите, чтобы пользовательские настройки дополнительно включали source $HOME/.zshrcи т.д. в программу .zshrc, тоже. Эта настройка поддерживается, так как файлы за пределами каталога программы не изменяются.


В качестве последнего дополнения, вот еще одно доказательство того, как приветствовать новичка. Используйте следующий код в вашем /program/dir/.zshenvконфигурационном файле rc:

echo define precmd, traps, etc.

autoload -Uz zsh-newuser-install

if [[ ! -e "$HOME/.zshrc" ]]; then
  zsh-newuser-install -f
  mv $ZDOTDIR/.zshrc $HOME/.zshrc
else
  builtin source $HOME/.zshrc
fi
МРУ
источник
Это я понял. Проблема в том, как определить крюк precmd через переменную окружения? Есть ли механизм добавления хуков или кода без изменения файлов? Или как мне сделать это, по крайней мере, без записи в глобальный и глобальный пользовательский ".zprofile" и подобные файлы? Например, я могу добавить свой собственный .zprofile, который не заменит существующие?
Шнацель
1
Кроме того, использование вами крюка precmd здесь заменит любые уже существующие крючки precmd; Zsh документы упоминают, что я могу создать массив функций, которые будут сосуществовать, но я понятия не имею, как это сделать.
Шнацель
1
(1) Что вы подразумеваете под тем, как я определяю ловушку precmd через переменную окружения? Пример, который я представил, работает IMHO как механизм bash. (2) Вы можете добавить хук через командную строку, но тогда он не является постоянным. В чем проблема с твоей модификацией .zshrc? (3) Пример: foo() { echo foo }; bar() { echo bar }; precmd_functions=(foo bar)выполняется foo()и bar() в дополнение к precmd().
mpy
2
Хорошо, это многое проясняет - тогда будет минимальный пример для bash PROMPT_COMMAND="echo foo" bash, верно? Это возможность для нереста ЗШ: ZDOTDIR=/program/dir zsh. Затем /program/dir/.zshrcзапускается при запуске, где вы можете определить крюк precmd (). Если вы хотите, чтобы пользователь дополнительно включал source $HOME/.zshrcи т.д. в zshrc программы. Это должно быть легко поддерживать, поскольку никакие файлы вне директории программы не изменяются.
mpy
1
@Shnatsel: я расширил свой ответ. Возможно, вы также можете отредактировать свой вопрос, чтобы включить дополнительную информацию из ваших комментариев.
mpy
5

Как утверждает @mypy, Zsh precmdработает аналогично Bash PROMPT_COMMAND.

Вот пример, который работает для Bash или Zsh и не использует eval:

## ~/myprompt.sh

# 'ZSH_VERSION' only defined in Zsh
# 'precmd' is a special function name known to Zsh

[ ${ZSH_VERSION} ] && precmd() { myprompt; }

# 'BASH_VERSION' only defined in Bash
# 'PROMPT_COMMAND' is a special environment variable name known to Bash

[ ${BASH_VERSION} ] && PROMPT_COMMAND=myprompt

# function called every time shell is about to draw prompt
myprompt() {
  if [ ${ZSH_VERSION} ]; then
    # Zsh prompt expansion syntax
    PS1='%{%F{red}%}%n%{%f%}@%{%F{red}%}%m %{%F{cyan}%}%~ %{%F{white}%}%# %{%f%}'
  elif [ ${BASH_VERSION} ]; then
    # Bash prompt expansion syntax
    PS1='\[\e[31m\]\u\[\e[0m\]@\[\e[31m\]\h \[\e[36m\]\w \[\e[37m\]\$ \[\e[0m\]'
  fi
}

Запустить из сценариев инициализации оболочки:

## ~/.bashrc
. ~/myprompt.sh

и:

## ~/.zshrc
. ~/myprompt.sh

Подсказки здесь - только примеры. Определенно можно делать гораздо более хитрые вещи.

Подробнее о настройке функций приглашения см. По адресу : http://zsh.sourceforge.net/Doc/Release/Functions.html#index-precmd и http://www.gnu.org/software/bash/manual/bashref.html. # Печать-Подсказка .

Для получения подробной информации о расширении приглашений см. Http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html и http://www.gnu.org/software/bash/manual/bashref.html#Printing-a. -Повторный .

jwfearn
источник