La variabile HISTCMD
viene aggiornato ogni volta che viene eseguito un nuovo comando . Sfortunatamente, il valore è mascherato durante l'esecuzione di PROMPT_COMMAND
(suppongo per motivi legati al fatto di non avere cronologia incasinata con cose che accadono nel comando prompt). La soluzione che ho trovato è un po 'disordinata, ma sembra che funzioni nei miei test limitati.
# This only works if the prompt has a prefix
# which is displayed before the status code field.
# Fortunately, in this case, there is one.
# Maybe use a no-op prefix in the worst case (!)
PS1_base=$'\n'
# Functions for PROMPT_COMMAND
PS1_update_HISTCMD() {
# If HISTCONTROL contains "ignoredups" or "ignoreboth", this breaks.
# We should not change it programmatically
# (think principle of least astonishment etc)
# but we can always gripe.
case :$HISTCONTROL: in
*:ignoredups:* | *:ignoreboth:*)
echo "PS1_update_HISTCMD(): HISTCONTROL contains 'ignoredups' or 'ignoreboth'" >&2
echo "PS1_update_HISTCMD(): Warning: Please remove this setting." >&2 ;;
esac
# PS1_HISTCMD needs to contain the old value of PS1_HISTCMD2 (a copy of HISTCMD)
PS1_HISTCMD=${PS1_HISTCMD2:-$PS1_HISTCMD}
# PS1_HISTCMD2 needs to be unset for the next prompt to trigger properly
unset PS1_HISTCMD2
}
PROMPT_COMMAND=PS1_update_HISTCMD
# Finally, the actual prompt:
PS1='${PS1_base#foo${PS1_HISTCMD2:=${HISTCMD%$PS1_HISTCMD}}}${_:+${PS1_HISTCMD2:+$? }}$ '
La logica nel prompt è approssimativamente come segue:
${PS1_base#foo...}
Questo visualizza il prefisso. Il materiale in #...
è utile solo per i suoi effetti collaterali.Vogliamo eseguire alcune manipolazioni variabili senza visualizzare i valori delle variabili, quindi le nascondiamo in una sostituzione di stringhe. (Verrà visualizzata cose strane e possibilmente spettacolari se il valore di PS1_base
accade mai per cominciare foo
seguita dall'indice cronologia dei comandi corrente.)
${PS1_HISTCMD2:=...}
Questo assegna un valore a PS1_HISTCMD2
(se non è impostata, che abbiamo hanno fatto sì che sia). La sostituzione dovrebbe anche espandersi nominalmente al nuovo valore, ma l'abbiamo nascosto in un ${var#subst}
come spiegato sopra.
${HISTCMD%$PS1_HISTCMD}
Si assegna sia il valore di HISTCMD
(quando una nuova voce nella cronologia dei comandi è stato fatto, cioè stiamo eseguendo un nuovo comando) o una stringa vuota (quando il comando è vuota) per PS1_HISTCMD2
. Ciò funziona eliminando il valore HISTCMD
qualsiasi corrispondenza su PS1_HISTCMD
(utilizzando la sintassi di sostituzione del suffisso ${var%subst}
).
${_:+...}
Questo è dalla domanda. Si espanderà a ... qualcosa se il valore di $_
è impostato e non vuoto (che è quando viene eseguito un comando, ma non per esempio se stiamo eseguendo un'assegnazione di variabile). Il "qualcosa" dovrebbe essere il codice di stato (e uno spazio, per la leggibilità) se PS1_HISTCMD2
non è vuoto.
${PS1_HISTCMD2:+$? }
Là.
'$ '
questo è solo il suffisso prompt di vero e proprio, come nel domanda iniziale.
Così le parti principali sono le variabili PS1_HISTCMD
, che ricorda il valore precedente di HISTCMD
, e la variabile PS1_HISTCMD2
che cattura il valore di HISTCMD
modo che possa essere accessibile da dentro PROMPT_COMMAND
, ma ha bisogno di essere impostata in PROMPT_COMMAND
in modo che il L'assegnazione ${PS1_HISTCMD2:=...}
si attiverà di nuovo la volta successiva che viene visualizzato il prompt.
Ho smanettato un po 'cercando di nascondere l'output da ${PS1_HISTCMD2:=...}
ma poi mi sono reso conto che in realtà c'è qualcosa che vogliamo mostrare comunque, quindi basta su quello. Non è possibile avere uno PS1_base
completamente vuoto perché la shell apparentemente nota e non tenta nemmeno di eseguire una sostituzione quando non c'è alcun valore; ma forse puoi inventare un valore fittizio (una sequenza di fuga senza uscita, forse?) se non hai altro da mostrare. O forse questo potrebbe essere refactored per funzionare con un suffisso invece; ma probabilmente sarà ancora più complicato.
In risposta alla "risposta più piccola" di Anubhava, ecco il codice senza commenti o controllo degli errori.
PS1_base=$'\n'
PS1_update_HISTCMD() { PS1_HISTCMD=${PS1_HISTCMD2:-$PS1_HISTCMD}; unset PS1_HISTCMD2; }
PROMPT_COMMAND=PS1_update_HISTCMD
PS1='${PS1_base#foo${PS1_HISTCMD2:=${HISTCMD%$PS1_HISTCMD}}}${_:+${PS1_HISTCMD2:+$? }}$ '
La trappola 'debug' non attiva su una riga di comando vuota, neanche. – chepner
@chepner 'trap 'echo hello' DEBUG' dice' ciao' ogni volta che premo invio. – yellowantphil
Hm, si attiva solo per me su una riga vuota se 'PROMPT_COMMAND' esegue un comando, nel qual caso sembra sparare due volte. (Una volta per il comando vuoto, e una volta per ogni comando eseguito tramite 'PROMPT_COMMAND'.) – chepner