¿Cuál es el equivalente ZSH de $ PROMPT_COMMAND de BASH?

24

BASH admite una $PROMPT_COMMANDvariable de entorno que define un comando que se ejecutará antes de cualquier solicitud interactiva de primer nivel. Estoy buscando un ZSH equivalente a eso.

La documentación dice que hay una función precmdque puedo definir para lograr eso; Sin embargo, no tengo idea de cómo definirlo a partir de una variable de entorno.

He considerado pasar una variable de entorno que haría que ZSH lea un archivo que contiene la definición de esa función, pero ZSH no parece admitir tales cosas : solo lee archivos globales y luego archivos por usuario. Puedo reemplazarlos pero no puedo agregarlos sin modificar los archivos, lo cual no puedo hacer.

Entonces, ¿cómo defino un enlace de solicitud previa en ZSH a través de una variable de entorno, como lo haría con $PROMPT_COMMANDBASH?

Shnatsel
fuente
A decir verdad, necesito un gancho posterior a la ejecución de comandos interactivos, pero ninguno de los shell proporciona uno, por lo que tengo que recurrir a ganchos de solicitud previa: parecen estar lo más cerca posible.
Shnatsel
1
Hm, me pregunto, cuál es la diferencia entre la ejecución de comandos post-interactivos y pre-prompt . Aparte de una diferencia conceptual, ¿dónde observas realmente una diferencia? (Vamos a omitir los comandos exity exec, ok ;))
mpy
@mpy hay una diferencia al ejecutar un trabajo en segundo plano, porque los trabajos en segundo plano son independientes de la secuencia de solicitud.
Shnatsel
1
Ok, entendí ese punto. Entonces, ¿qué tal algo así: start() { eval "$@"; echo post-command-code }y luego usar un enlace zle para ejecutar la línea de comando con startantepuesto?
mpy
1
La DEBUGtrampa es un buen hallazgo, pero aún tienes el problema de cómo definirla. He extendido mi respuesta una vez más, pero te dejo escribir tu propia respuesta con respecto a la solución de trampa DEBUG. :)
mpy

Respuestas:

24

El enfoque más simple para emular bash $PROMPT_COMMANDque me viene a la mente es usar el precmdgancho, como ya descubriste. Defínalo como

precmd() { eval "$PROMPT_COMMAND" }

y puedes hacer algo así:

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

Tenga en cuenta las comillas simples en ese ejemplo, de lo contrario $(date)se ampliará demasiado pronto, es decir, ya al definir $PROMPT_COMMANDy no cuando se llama antes de la solicitud.


Si desea preservar (y no quiere alterar) la definición existente, puede usar ese enfoque:

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

Con eso, las prmptcmdfunciones se ejecutan después de la precmd()función existente .


Finalmente, aquí hay una manera adecuada para usar en un paquete de programa, que no debe modificar los archivos del usuario o del sistema ni puede ingresar los comandos interactivos.

Un ejemplo para generar una sesión bash podría ser

PROMPT_COMMAND="echo foo" bash

Para generar zsh puedes usar

ZDOTDIR=/program/dir zsh

lo que hace /program/dir/.zshrcque sea de origen. En este archivo, el precmd()gancho se puede definir como se explicó anteriormente. Si desea que la configuración del usuario, además, incluya source $HOME/.zshrcetc. en el programa .zshrc, también. Esta configuración se puede mantener, ya que no se modifican archivos fuera del directorio del programa.


Como última adición, aquí hay una prueba de concepto de cómo mantener al nuevo usuario bienvenido también. Use el siguiente código en su /program/dir/.zshenvarchivo de configuración 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
fuente
Eso me lo imaginé. El problema es: ¿cómo defino el enlace precmd a través de una variable de entorno? ¿Existe un mecanismo para agregar ganchos o código sin modificar archivos? ¿O cómo lo hago al menos sin escribir en el archivo ".zprofile" global y del usuario global y archivos similares? Como, ¿puedo agregar mi propio .zprofile que no reemplazará a los existentes?
Shnatsel
1
También su uso del gancho precmd aquí reemplazaría cualquier gancho precmd ya existente; Los documentos de zsh mencionan que puedo hacer una serie de funciones que coexistirán, pero no tengo idea de cómo hacerlo.
Shnatsel
1
(1) ¿Qué quiere decir con cómo defino el gancho precmd a través de una variable de entorno? El ejemplo que presenté funciona en mi humilde opinión como mecanismo bash. (2) Puede agregar el gancho a través de la línea de comandos, pero no es permanente. ¿Cuál es el problema con la modificación de tu .zshrc? (3) Un ejemplo: foo() { echo foo }; bar() { echo bar }; precmd_functions=(foo bar)esto se ejecuta foo()y bar() además de precmd().
mpy
2
Ok, eso aclara mucho: un ejemplo mínimo para bash sería PROMPT_COMMAND="echo foo" bash, ¿verdad? ¿Es esto una posibilidad para el desove zsh: ZDOTDIR=/program/dir zsh. Luego /program/dir/.zshrcse obtiene al inicio, donde puede definir el gancho precmd (). Si desea que el usuario además incluya source $HOME/.zshrcetc. en el programa zshrc. Esto debería ser fácil de mantener, ya que no se modifican archivos fuera del directorio del programa.
mpy
1
@Shnatsel: extendí mi respuesta. Quizás también pueda editar su pregunta para incluir la información adicional de sus comentarios.
mpy
5

Como dice @mypy, Zsh's precmdfunciona de manera similar a Bash PROMPT_COMMAND.

Aquí hay un ejemplo que funciona para Bash o Zsh y no 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
}

Ejecutar desde scripts de inicio de shell:

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

y:

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

Las indicaciones aquí son solo ejemplos. Definitivamente, uno puede hacer cosas mucho más difíciles.

Para obtener detalles sobre cómo configurar las funciones de solicitud, consulte: http://zsh.sourceforge.net/Doc/Release/Functions.html#index-precmd y http://www.gnu.org/software/bash/manual/bashref.html # Imprimiendo un mensaje .

Para obtener detalles sobre las expansiones rápidas, consulte http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html y http://www.gnu.org/software/bash/manual/bashref.html#Printing-a -Prompt .

jwfearn
fuente