Jaki jest odpowiednik ZSH dla $ PROMPT_COMMAND BASH?

24

BASH obsługuje $PROMPT_COMMANDzmienną środowiskową, która definiuje polecenie, które należy wykonać przed dowolnym interaktywnym monitem pierwszego poziomu. Szukam ekwiwalentu tego ZSH.

Dokumentacja mówi, że istnieje funkcja, precmdktórą mogę zdefiniować, aby ją osiągnąć; nie mam jednak pojęcia, jak to zdefiniować na podstawie zmiennej środowiskowej.

Rozważałem przekazanie zmiennej środowiskowej, która zmusiłaby ZSH do odczytania pliku zawierającego definicję tej funkcji, ale ZSH nie wydaje się obsługiwać takich rzeczy : odczytuje tylko pliki globalne, a następnie pliki poszczególnych użytkowników. Mogę je zastąpić, ale nie mogę ich dodać bez modyfikacji plików, czego nie mogę zrobić.

Jak więc zdefiniować przechwytywanie przed monitem w ZSH za pomocą zmiennej środowiskowej, tak jak zrobiłbym to $PROMPT_COMMANDw BASH?

Shnatsel
źródło
Prawdę mówiąc, potrzebuję haka po interaktywnym wykonaniu polecenia, ale żadna powłoka go nie zapewnia, więc muszę uciekać się do wcześniejszych haczyków - wydają się być tak blisko, jak to możliwe.
Shnatsel
1
Hm, zastanawiam się, jaka jest różnica między wykonaniem polecenia po interakcyjnym a wstępnym monitem . Oprócz różnicy pojęciowej, gdzie widzisz różnicę. ( exitexec;)
Pomińmy
@ mpy jest różnica podczas uruchamiania zadania w tle, ponieważ zadania w tle są niezależne od sekwencji pytań.
Shnatsel
1
Ok, rozumiem. A co powiesz na coś takiego: start() { eval "$@"; echo post-command-code }a następnie skorzystaj z wiązania zle, aby wykonać wiersz komend z startrozszerzonym?
mpy
1
DEBUGPułapka jest miły znaleźć, ale nadal masz problem, jak go zdefiniować. Ponownie udzieliłem odpowiedzi, ale pozostawiam wam napisanie własnej odpowiedzi dotyczącej rozwiązania pułapki DEBUG. :)
mpy

Odpowiedzi:

24

Najprostszym sposobem na emulację basha, $PROMPT_COMMANDktóry przychodzi mi do głowy, jest użycie precmdhaka, jak już się zorientowałeś. Zdefiniuj to jako

precmd() { eval "$PROMPT_COMMAND" }

i możesz zrobić coś takiego:

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

Zwróć uwagę na pojedyncze cudzysłowy w tym przykładzie, w przeciwnym razie $(date)zostaną rozwinięte zbyt wcześnie, tj. Już podczas definiowania, $PROMPT_COMMANDa nie po wywołaniu przed pytaniem.


Jeśli chcesz zachować (i nie chcesz zmieniać) istniejącą definicję, możesz zastosować to podejście:

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

Dzięki temu prmptcmdfunkcje są wykonywane po istniejącej precmd()funkcji.


Wreszcie, oto sposób, który jest odpowiedni do użycia w pakiecie programu, który nie powinien modyfikować plików użytkownika ani plików systemowych ani wprowadzać interaktywnych poleceń.

Przykładem odrodzenia sesji bash może być

PROMPT_COMMAND="echo foo" bash

Do spawnowania zsh możesz użyć

ZDOTDIR=/program/dir zsh

który powoduje /program/dir/.zshrcpozyskiwanie. W tym pliku precmd()zaczep można zdefiniować jak wyjaśniono powyżej. Jeśli chcesz, aby ustawienia użytkownika dodatkowo zawierały source $HOME/.zshrcitp. W .zshrc programu. Ta konfiguracja jest możliwa do utrzymania, ponieważ żadne pliki poza katalogiem programu nie są modyfikowane.


Jako ostatni dodatek, oto dowód koncepcji, jak powitać nowego użytkownika również. Użyj następującego kodu w /program/dir/.zshenvpliku konfiguracyjnym 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
źródło
Tyle pomyślałem. Problem polega na tym - jak zdefiniować hak precmd za pomocą zmiennej środowiskowej? Czy istnieje mechanizm dodawania haków lub kodu bez modyfikowania plików? Lub jak to zrobić przynajmniej bez zapisywania w globalnym i globalnym pliku „.zprofile” i podobnych plikach? Czy mogę dodać własny plik .zprofile, który nie zastąpi istniejących?
Shnatsel
1
Również użycie tutaj haka precmd zastąpiłoby wszelkie istniejące już haki precmd; Dokumenty zsh wspominają, że mogę stworzyć tablicę funkcji, które będą współistnieć, ale nie mam pojęcia, jak to zrobić.
Shnatsel
1
(1) Co masz na myśli przez to, jak zdefiniować hook precmd za pomocą zmiennej środowiskowej? Przykład, który przedstawiłem działa IMHO jak mechanizm bash. (2) Możesz dodać hak za pomocą wiersza poleceń, ale wtedy nie jest to stałe. Jaki jest problem z modyfikacją twojego .zshrc? (3) Na przykład: foo() { echo foo }; bar() { echo bar }; precmd_functions=(foo bar)To Wykonuje foo()i bar() dodatkowo do precmd().
mpy
2
Ok, to dużo wyjaśnia - byłby to minimalny przykład bash PROMPT_COMMAND="echo foo" bash, prawda? Jest to możliwość dla tarła zsh: ZDOTDIR=/program/dir zsh. Następnie /program/dir/.zshrcna początku jest pozyskiwany, gdzie można zdefiniować hak precmd (). Jeśli chcesz, aby użytkownik dodatkowo uwzględnił source $HOME/.zshrcitp. W programie zshrc. Powinno to być łatwe w utrzymaniu, ponieważ żadne pliki poza katalogiem programu nie są modyfikowane.
mpy
1
@Shnatsel: Rozszerzyłem swoją odpowiedź. Być może możesz również edytować swoje pytanie, aby uwzględnić dodatkowe informacje z komentarzy.
mpy
5

Jak stwierdza @mypy, Zsh precmddziała podobnie do Basha PROMPT_COMMAND.

Oto przykład, który działa dla Bash lub Zsh i nie używa 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
}

Uruchom ze skryptów inicjujących powłokę:

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

i:

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

Podpowiedzi tutaj są tylko przykładami. Z pewnością można zrobić znacznie trudniejsze rzeczy.

Aby uzyskać szczegółowe informacje na temat ustawiania funkcji pytania, patrz: http://zsh.sourceforge.net/Doc/Release/Functions.html#index-precmd i http://www.gnu.org/software/bash/manual/bashref.html # Drukowanie-Monituj .

Aby uzyskać szczegółowe informacje na temat szybkich rozszerzeń, zobacz http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html i http://www.gnu.org/software/bash/manual/bashref.html#Printing-a -Prompt .

jwfearn
źródło