Was ist das ZSH-Äquivalent von $ PROMPT_COMMAND in BASH?

24

BASH unterstützt eine $PROMPT_COMMANDUmgebungsvariable, die einen Befehl definiert, der vor jeder interaktiven Eingabeaufforderung der ersten Ebene ausgeführt werden soll. Ich suche ein ZSH-Äquivalent davon.

Die Dokumentation besagt, dass es eine Funktion gibt, die precmdich definieren kann, um dies zu erreichen. Ich habe jedoch keine Ahnung, wie man es aus einer Umgebungsvariablen definiert.

Ich habe überlegt, eine Umgebungsvariable zu übergeben, mit der ZSH eine Datei mit der Definition dieser Funktion lesen würde, aber ZSH scheint solche Dinge nicht zu unterstützen : Es werden nur globale Dateien und dann benutzerspezifische Dateien gelesen. Ich kann sie ersetzen, aber nicht hinzufügen, ohne die Dateien zu ändern, was ich nicht kann.

Wie definiere ich in ZSH einen Hook vor der Eingabeaufforderung über eine Umgebungsvariable, wie ich es $PROMPT_COMMANDin BASH tun würde?

Shnatsel
quelle
Um ehrlich zu sein, ich brauche einen Hook für die Ausführung von Befehlen nach der Interaktion, aber keine der Shells bietet einen, sodass ich auf Hooks vorab zurückgreifen muss - sie scheinen so nah wie möglich zu sein.
Shnatsel
1
Hm, ich frage mich, was der Unterschied zwischen post-interaktiver Befehlsausführung und Pre-Prompt ist. Abgesehen von einem konzeptuellen Unterschied, wo beobachten Sie tatsächlich einen Unterschied. (Lassen wir die Befehle exitexec;)
weg
@mpy Beim Ausführen eines Hintergrundjobs gibt es einen Unterschied, da Hintergrundjobs von der Eingabeaufforderungsreihenfolge unabhängig sind.
Shnatsel
1
Ok, ich habe diesen Punkt verstanden. Also, wie wäre es mit so etwas: start() { eval "$@"; echo post-command-code }und verwenden Sie dann eine Zle-Bindung, um die Befehlszeile mit startvorangestelltem auszuführen ?
mpy
1
Die DEBUGFalle ist eine nette Entdeckung, aber Sie haben immer noch das Problem, wie man sie definiert. Ich habe meine Antwort noch einmal erweitert, aber ich überlasse es Ihnen, Ihre eigene Antwort in Bezug auf die DEBUG-Trap-Lösung zu schreiben. :)
mpy

Antworten:

24

Der einfachste Ansatz, um Bashs zu emulieren, $PROMPT_COMMANDder mir in den Sinn kommt, ist die Verwendung des precmdHooks, wie Sie bereits herausgefunden haben. Definiere es als

precmd() { eval "$PROMPT_COMMAND" }

und Sie können so etwas tun:

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

Bitte beachten Sie die einfachen Anführungszeichen in diesem Beispiel, da diese sonst $(date)zu früh, dh bereits beim Definieren $PROMPT_COMMANDund nicht beim Aufrufen vor der Eingabeaufforderung, erweitert werden.


Wenn Sie die vorhandene Definition beibehalten (und nicht ändern) möchten, können Sie diesen Ansatz verwenden:

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

Damit werden die prmptcmdFunktionen nach der vorhandenen precmd()Funktion ausgeführt.


Schließlich ist hier ein Weg, der zur Verwendung in einem Programmpaket geeignet ist, das weder Benutzer- oder Systemdateien modifizieren sollte noch die Befehle interaktiv eingeben kann.

Ein Beispiel für das Starten einer Bash-Sitzung könnte sein

PROMPT_COMMAND="echo foo" bash

Um zsh zu erzeugen, können Sie verwenden

ZDOTDIR=/program/dir zsh

welches veranlasst /program/dir/.zshrc, beschafft zu werden. In dieser Datei kann der precmd()Hook wie oben beschrieben definiert werden. Wenn Sie möchten , die Einstellungen des Benutzers zusätzlich enthalten source $HOME/.zshrcusw. in dem .zshrc Programm auch. Dieses Setup kann beibehalten werden, da keine Dateien außerhalb des Programmverzeichnisses geändert werden.


Als letzte Ergänzung finden Sie hier einen Proof-of-Concept, wie Sie den neuen Benutzer ebenfalls willkommen heißen können. Verwenden Sie den folgenden Code in Ihrer /program/dir/.zshenvRC-Konfigurationsdatei:

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
quelle
So viel habe ich mir gedacht. Das Problem ist - wie definiere ich den Precmd-Hook über eine Umgebungsvariable? Gibt es einen Mechanismus zum Hinzufügen von Hooks oder Code, ohne dass Dateien geändert werden müssen? Oder wie mache ich das zumindest, ohne in die globalen und benutzer-globalen ".zprofile" und ähnliche Dateien zu schreiben? Kann ich mein eigenes .z-Profil hinzufügen, das vorhandene nicht ersetzt?
Shnatsel
1
Auch Ihre Verwendung von precmd hook hier würde bereits vorhandene precmd hooks ersetzen. zsh docs erwähnen, dass ich eine Reihe von Funktionen erstellen kann, die nebeneinander existieren, aber ich habe keine Ahnung, wie das geht.
Shnatsel
1
(1) Was meinst du mit wie definiere ich den Precmd Hook über eine Umgebungsvariable? Das Beispiel, das ich vorgestellt habe, funktioniert IMHO wie ein Bash-Mechanismus. (2) Sie können den Hook über die Befehlszeile hinzufügen, er ist dann aber nicht permanent. Was ist das Problem mit der Änderung Ihrer .zshrc? (3) Ein Beispiel: foo() { echo foo }; bar() { echo bar }; precmd_functions=(foo bar)Dies wird ausgeführt foo()und bar() zusätzlich zu precmd().
mpy
2
Ok, das macht vieles klar - ein minimales Beispiel für Bash wäre dann PROMPT_COMMAND="echo foo" bash, oder? Ist das eine Möglichkeit zum Laichen zsh: ZDOTDIR=/program/dir zsh. /program/dir/.zshrcWird dann beim Start bezogen, wo Sie den Haken precmd () definieren können. Wenn Sie möchten source $HOME/.zshrc, fügen Sie dem Benutzer zusätzlich usw. in das zshrc des Programms hinzu. Dies sollte einfach zu warten sein, da keine Dateien außerhalb des Programmverzeichnisses geändert werden.
mpy
1
@Shnatsel: Ich habe meine Antwort erweitert. Vielleicht können Sie Ihre Frage auch bearbeiten, um die zusätzlichen Informationen aus Ihren Kommentaren aufzunehmen.
mpy
5

Wie @mypy angibt, funktioniert Zshs precmdähnlich wie Bashs PROMPT_COMMAND.

Hier ist ein Beispiel, das für Bash oder Zsh funktioniert und nicht verwendet wird 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
}

Führen Sie von Shell-Init-Skripten aus:

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

und:

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

Die Aufforderungen hier sind nur Beispiele. Man kann definitiv viel kniffligere Sachen machen.

Einzelheiten zum Festlegen von Eingabeaufforderungsfunktionen finden Sie unter: http://zsh.sourceforge.net/Doc/Release/Functions.html#index-precmd und http://www.gnu.org/software/bash/manual/bashref.html # Sofortdruck .

Ausführliche Informationen zu Eingabeaufforderungserweiterungen finden Sie unter http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html und http://www.gnu.org/software/bash/manual/bashref.html#Printing-a -Prompt .

jwfearn
quelle