Zmienna HISTCMD
jest aktualizowana za każdym razem nowa komenda jest wykonywana . Niestety, wartość jest maskowana podczas wykonywania PROMPT_COMMAND
(przypuszczam, że z powodów związanych z tym, że historia nie zawodziła z rzeczami, które zdarzają się w poleceniu polecenia). Obejście problemu, które wymyśliłem, jest trochę nieporządne, ale wydaje się działać w moich ograniczonych testach.
# 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:+$? }}$ '
Logika w wierszu jest mniej więcej następująco:
${PS1_base#foo...}
Wyświetla prefiks. Rzeczy w #...
są użyteczne tylko ze względu na efekty uboczne.Chcemy wykonać pewne zmienne manipulacje bez wyświetlania wartości zmiennych, więc ukrywamy je w substytucji łańcuchowej. (Spowoduje to wyświetlenie nieparzyste i ewentualnie spektakularne rzeczy, jeżeli wartość PS1_base
nie dzieje zacząć foo
następnie bieżącego indeksu historii poleceń.)
${PS1_HISTCMD2:=...}
ta przypisuje wartość do PS1_HISTCMD2
(jeśli nie jest ustawiona, co my upewniłem się, że tak jest). Zastąpienie nominalnie również rozszerzyłoby się do nowej wartości, ale ukryliśmy je w ${var#subst}
, jak wyjaśniono powyżej.
${HISTCMD%$PS1_HISTCMD}
Mamy przypisać albo wartość HISTCMD
(gdy nowy wpis w historii poleceń jest dokonywana, czyli realizujemy nową komendę) lub pusty ciąg (gdy polecenie jest pusty) do PS1_HISTCMD2
. Działa to poprzez przycięcie wartości HISTCMD
dowolnego dopasowania na PS1_HISTCMD
(przy użyciu składni zastępczej przyrostka ${var%subst}
).
${_:+...}
To jest pytanie. Rozszerzy się do ... czegoś, jeśli ustawiona jest wartość $_
i jest niepustą (co jest, gdy wykonywane jest polecenie, ale nie na przykład, jeśli wykonujemy przypisanie zmiennych). "Coś" powinno być kodem statusu (i spacji, dla czytelności), jeśli PS1_HISTCMD2
jest niepustą.
${PS1_HISTCMD2:+$? }
Tam.
'$ '
To jest tylko rzeczywisty sufiks polecenia, tak jak w pytaniu oryginalnym.
Więc najważniejsze części są zmienne PS1_HISTCMD
który pamięta poprzednią wartość HISTCMD
, a zmienna PS1_HISTCMD2
który rejestruje wartość HISTCMD
więc może być dostępne od wewnątrz PROMPT_COMMAND
, ale musi być wyłączony w PROMPT_COMMAND
tak że ${PS1_HISTCMD2:=...}
Przypisanie zostanie ponownie uruchomione po następnym wyświetleniu monitu.
Trochę przezwyciężyłem próbę ukrycia wyjścia z ${PS1_HISTCMD2:=...}
, ale potem zdałem sobie sprawę, że w rzeczywistości jest coś, co chcemy wyświetlić w każdym razie, więc po prostu na tym pomóż. Nie możesz mieć całkowicie pustego PS1_base
, ponieważ powłoka najwyraźniej zauważa i nawet nie próbuje dokonać substytucji, gdy nie ma żadnej wartości; ale może uda ci się wymyślić wartość dummy (może być to sekwencja escape no-op?), jeśli nie masz nic innego, co chcesz wyświetlić. Lub może to być refaktoryzowane do uruchomienia z sufiksem zamiast; ale to prawdopodobnie będzie jeszcze trudniejsze.
W odpowiedzi na "najmniejszą odpowiedź" Anubhawy, oto kod bez komentarzy i sprawdzania błędów.
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:+$? }}$ '
Opcja 'pułapka DEBUG' nie wyzwala w pustym wierszu poleceń, albo. – chepner
@chepner 'trap 'echo hello' DEBUG' mówi" cześć "za każdym razem, gdy wciskam Enter. – yellowantphil
Hm, uruchamia się tylko dla mnie w pustym wierszu, jeśli 'PROMPT_COMMAND' wykonuje polecenie, w takim przypadku wydaje się, że wystrzelił dwukrotnie. (Raz dla pustego polecenia i raz dla każdego polecenia wykonanego przez 'PROMPT_COMMAND'.) – chepner