Qual è l'equivalente ZSH di $ PROMPT_COMMAND di BASH?


24

BASH supporta una $PROMPT_COMMANDvariabile di ambiente che definisce un comando da eseguire prima di qualsiasi prompt interattivo di primo livello. Sto cercando un ZSH equivalente di quello.

La documentazione dice che esiste una funzione precmdche posso definire per ottenerla; tuttavia, non ho idea di come definirlo da una variabile di ambiente.

Ho preso in considerazione l'idea di passare una variabile d'ambiente che farebbe leggere a ZSH un file contenente la definizione di quella funzione, ma ZSH non sembra supportare tali cose : legge solo i file globali e quindi i file per utente. Posso sostituirli ma non posso aggiungerli senza modificare i file, cosa che non posso fare.

Quindi, come posso definire un hook di pre-prompt in ZSH tramite una variabile d'ambiente, come farei usando $PROMPT_COMMANDBASH?


A dire la verità, ho bisogno di un hook post-interattivo-comando-esecuzione, ma nessuna delle due shell ne fornisce uno quindi devo ricorrere a hook pre-prompt: sembrano essere il più vicino possibile.
Shnatsel,

1
Hm, mi chiedo, qual è la differenza tra esecuzione post-interattiva-comando e pre-prompt . A parte una differenza concettuale, dove osservi effettivamente una differenza. ( exitexec;)
Omettiamo

@mpy c'è una differenza quando si esegue un lavoro in background, perché i lavori in background sono indipendenti dalla sequenza di prompt.
Shnatsel,

1
Ok, ho capito. Quindi, che ne dici di una cosa del genere: start() { eval "$@"; echo post-command-code }e quindi utilizzare un'associazione zle per eseguire la riga di comando con startanteposto?
mpy

1
La DEBUGtrappola è una bella scoperta, ma hai ancora il problema su come definirla. Ho esteso ancora una volta la mia risposta, ma lascio a te scrivere la tua risposta relativa alla soluzione trap DEBUG. :)
mpy,

Risposte:


24

L'approccio più semplice per emulare Bash's $PROMPT_COMMANDche mi viene in mente è usare l' precmdhook, come hai già capito. Definirlo come

precmd() { eval "$PROMPT_COMMAND" }

e puoi fare qualcosa del genere:

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

Si noti che le virgolette singole in questo esempio, altrimenti $(date)verranno espanse troppo presto, ovvero già durante la definizione $PROMPT_COMMANDe non quando vengono chiamate prima del prompt.


Se vuoi conservare (e non vuoi alterare) la definizione esistente, puoi usare questo approccio:

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

Con ciò le prmptcmdfunzioni vengono eseguite dopo la precmd()funzione esistente .


Infine, ecco un modo che è adatto per l'uso in un pacchetto di programma, che non dovrebbe né modificare i file utente o di sistema né inserire comandi interattivi.

Un esempio per generare una sessione bash potrebbe essere

PROMPT_COMMAND="echo foo" bash

Per generare zsh puoi usare

ZDOTDIR=/program/dir zsh

quale causa /program/dir/.zshrcproviene. In questo file l' precmd()hook può essere definito come spiegato sopra. Se si desidera che le impostazioni dell'utente in aggiunta includono source $HOME/.zshrcecc .zshrc del programma, anche. Questa configurazione è gestibile, poiché nessun file esterno alla directory del programma viene modificato.


Come ultima aggiunta, ecco una dimostrazione del concetto di come dare il benvenuto anche al nuovo utente. Usa il seguente codice nel tuo /program/dir/.zshenvfile di configurazione 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

Ho pensato tanto. Il problema è: come posso definire l'hook precmd tramite una variabile d'ambiente? Esiste un meccanismo per aggiungere hook o codice senza modificare i file? O come posso farlo almeno senza scrivere nel ".zprofile" globale e utente-globale e file simili? Ad esempio, posso aggiungere il mio .zprofile che non sostituirà quelli esistenti?
Shnatsel,

1
Anche il tuo uso di hook precmd qui sostituirà qualsiasi hook precmd già esistente; I documenti di zsh menzionano che posso creare una serie di funzioni che coesisteranno, ma non ho idea di come farlo.
Shnatsel,

1
(1) Cosa intendi con come definire l'hook precmd tramite una variabile d'ambiente? L'esempio che ho presentato funziona come IMHO come meccanismo bash. (2) È possibile aggiungere l'hook tramite riga di comando, ma non è permanente. Qual è il problema con la modifica del tuo .zshrc? (3) Un esempio: foo() { echo foo }; bar() { echo bar }; precmd_functions=(foo bar)questo viene eseguito foo()e bar() in aggiunta a precmd().
mpy

2
Ok, questo chiarisce molto: un esempio minimo di bash sarebbe PROMPT_COMMAND="echo foo" bash, giusto? È questa una possibilità per la deposizione delle uova zsh: ZDOTDIR=/program/dir zsh. Quindi /program/dir/.zshrcviene fornito all'avvio in cui è possibile definire l'hook precmd (). Se si desidera inoltre che l'utente includa source $HOME/.zshrcecc. Nello zshrc del programma. Questo dovrebbe essere facile da mantenere, poiché nessun file esterno alla directory del programma viene modificato.
mpy

1
@Shnatsel: ho esteso la mia risposta. Forse puoi anche modificare la tua domanda per includere le informazioni aggiuntive dai tuoi commenti.
mpy

5

Come afferma @mypy, Zsh precmdfunziona in modo simile a quello di Bash PROMPT_COMMAND.

Ecco un esempio che funziona per Bash o Zsh e che non utilizza 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
}

Esegui dagli script di shell shell:

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

e:

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

Le istruzioni qui sono solo esempi. Si può sicuramente fare cose molto più complicate.

Per i dettagli sull'impostazione delle funzioni del prompt, consultare: http://zsh.sourceforge.net/Doc/Release/Functions.html#index-precmd e http://www.gnu.org/software/bash/manual/bashref.html # Stampa-a-Prompt .

Per dettagli sulle espansioni rapide, consultare http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html e http://www.gnu.org/software/bash/manual/bashref.html#Printing-a -Prompt .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.