Qual é o equivalente ZSH de $ PROMPT_COMMAND do BASH?

24

O BASH suporta uma $PROMPT_COMMANDvariável de ambiente que define um comando a ser executado antes de qualquer prompt interativo de primeiro nível. Estou à procura de um equilíbrio ZSH disso.

A documentação diz que há uma função precmdque posso definir para conseguir isso; no entanto, não tenho idéia de como defini-lo a partir de uma variável de ambiente.

Eu considerei passar uma variável de ambiente que faria o ZSH ler um arquivo contendo a definição dessa função, mas o ZSH não suporta essas coisas : ele lê apenas arquivos globais e arquivos por usuário. Posso substituí-los, mas não posso adicioná-los sem modificar os arquivos, o que não posso fazer.

Então, como defino um gancho de pré-prompt no ZSH por meio de uma variável de ambiente, como faria usando o $PROMPT_COMMANDBASH?

Shnatsel
fonte
Para dizer a verdade, eu preciso de um gancho de execução de comando pós-interativo, mas nenhum shell fornece um, então eu tenho que recorrer a ganchos pré-prompt - eles parecem estar o mais perto possível.
Shnatsel 31/03
11
Hm, eu estou me perguntando, qual é a diferença entre execução de comando pós-interativa e pré-prompt . Além de uma diferença conceitual, onde você observa realmente uma diferença. (Vamos omitir os comandos exite exec, ok ;))
mpy
@mpy Há uma diferença ao executar um trabalho em segundo plano, porque os trabalhos em segundo plano são independentes da sequência de prompt.
Shnatsel 31/03
11
Ok, eu entendi esse ponto. Então, que tal algo assim: start() { eval "$@"; echo post-command-code }e depois use um zle-binding para executar a linha de comando com o startprefixo?
Mpy
11
A DEBUGarmadilha é uma boa descoberta, mas você ainda tem o problema de defini-la. Estendi minha resposta mais uma vez, mas deixo para você escrever sua própria resposta sobre a solução de interceptação DEBUG. :)
Mpy #

Respostas:

24

A abordagem mais simples para emular o bash, $PROMPT_COMMANDque me vem à mente, é usar o precmdgancho, como você já descobriu. Defina-o como

precmd() { eval "$PROMPT_COMMAND" }

e você pode fazer algo assim:

$ 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     
$

Observe as aspas simples nesse exemplo; caso contrário, ele $(date)será expandido muito cedo, ou seja, já ao definir $PROMPT_COMMANDe não quando chamado antes do prompt.


Se você deseja preservar (e não deseja alterar) a definição existente, pode usar essa abordagem:

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

Com isso, as prmptcmdfunções são executadas após a precmd()função existente .


Finalmente, aqui está uma maneira que é adequada para uso em um pacote de programas, que não deve modificar arquivos de usuário ou sistema nem pode inserir os comandos interativos.

Um exemplo para gerar uma sessão bash pode ser

PROMPT_COMMAND="echo foo" bash

Para gerar o zsh, você pode usar

ZDOTDIR=/program/dir zsh

o que causa /program/dir/.zshrca origem. Neste arquivo, o precmd()gancho pode ser definido como explicado acima. Se você deseja que as configurações do usuário também incluam source $HOME/.zshrcetc. no .zshrc do programa, também. Essa configuração é sustentável, pois nenhum arquivo fora do diretório do programa é modificado.


Como última adição, aqui está uma prova de conceito de como manter o novo usuário bem-vindo também. Use o seguinte código no seu /program/dir/.zshenvarquivo de configuração 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
mpy
fonte
Isso eu imaginei. O problema é - como defino o gancho precmd por meio de uma variável de ambiente? Existe um mecanismo para adicionar ganchos ou código sem modificar arquivos? Ou como faço isso pelo menos sem gravar nos arquivos ".zprofile" global e global de usuário e similares? Como, posso adicionar meu próprio .zprofile que não substituirá os existentes?
Shnatsel 31/03
11
Além disso, o uso do gancho precmd aqui substitui todos os ganchos precmd existentes; Os documentos do zsh mencionam que posso criar uma série de funções que coexistirão, mas não tenho idéia de como fazer isso.
Shnatsel 31/03
11
(1) O que você quer dizer com como defino o gancho precmd por meio de uma variável de ambiente? O exemplo que apresentei funciona IMHO como mecanismo de bash. (2) Você pode adicionar o gancho via linha de comando, mas não é permanente. Qual é o problema com a modificação do seu .zshrc? (3) Um exemplo: foo() { echo foo }; bar() { echo bar }; precmd_functions=(foo bar)Isso executa foo()e bar() além de precmd().
Mpy
2
Ok, isso esclarece muito - um exemplo mínimo para o bash seria PROMPT_COMMAND="echo foo" bash, certo? Será esta uma possibilidade de desova zsh: ZDOTDIR=/program/dir zsh. Em seguida, /program/dir/.zshrcé originado no início, onde você pode definir o gancho precmd (). Se você deseja que o usuário além disso inclua source $HOME/.zshrcetc. no zshrc do programa. Isso deve ser fácil de manter, pois nenhum arquivo fora do diretório do programa é modificado.
Mpy #
11
@ Snatsel: Eu estendi minha resposta. Talvez você também possa editar sua pergunta para incluir as informações adicionais de seus comentários.
Mpy #
5

Como @mypy afirma, o Zsh's precmdfunciona da mesma forma que o Bash PROMPT_COMMAND.

Aqui está um exemplo que funciona para Bash ou Zsh e não usa 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
}

Execute a partir dos scripts shell init:

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

e:

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

As instruções aqui são apenas exemplos. Definitivamente, pode-se fazer coisas muito mais complicadas.

Para obter detalhes sobre a configuração de funções de prompt, consulte: http://zsh.sourceforge.net/Doc/Release/Functions.html#index-precmd e http://www.gnu.org/software/bash/manual/bashref.html # Imprimindo um prompt .

Para obter detalhes sobre expansões de prompt, consulte http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html e http://www.gnu.org/software/bash/manual/bashref.html#Printing-a -Prompt .

jwfearn
fonte