Czy w bash od wewnątrz PROMPT_COMMAND istnieje sposób, aby stwierdzić, czy użytkownik po prostu nacisnął „return” i nie wprowadził polecenia?
Czy w bash od wewnątrz PROMPT_COMMAND istnieje sposób, aby stwierdzić, czy użytkownik po prostu nacisnął „return” i nie wprowadził polecenia?
Odpowiedzi:
Sprawdź, czy numer historii został zwiększony. Anulowany monit lub monit, w którym użytkownik właśnie nacisnął Enter, nie zwiększy numeru historii.
Numer historii jest dostępny w zmiennej HISTCMD
, ale nie jest on dostępny w PROMPT_COMMAND
(ponieważ to, czego chcesz, to w rzeczywistości numer historii poprzedniego polecenia; polecenie, które wykonuje PROMPT_COMMAND
się nie ma numeru historii). Możesz uzyskać liczbę z wyjścia fc
.
prompt_command () {
HISTCMD_previous=$(fc -l -1); HISTCMD_previous=${HISTCMD_previous%%$'[\t ]'*}
if [[ -z $HISTCMD_before_last ]]; then
# initial prompt
elif [[ $HISTCMD_before_last = "$HISTCMD_previous" ]]; then
# cancelled prompt
else
# a command was run
fi
HISTCMD_before_last=$HISTCMD_previous
}
PROMPT_COMMAND='prompt_command'
Zauważ, że jeśli w historii włączyłeś squashowanie duplikatów ( HISTCONTROL=ignoredups
lub HISTCONTROL=erasedups
), to błędnie zgłosi puste polecenie po uruchomieniu dwóch identycznych poleceń kolejno.
${HISTCMD_previous%%$'[\t ]'*}
brakowało bitu $'…'
i skończyło się na skrócie po `,
t` lub spacji zamiast po tabulatorze lub spacji, ale bash drukuje tabulację.
Istnieje obejście, ale ma pewne wymagania:
Musisz ustawić $HISTCONTROL
zapisywanie WSZYSTKICH poleceń, a także duplikatów i spacji. Więc ustaw:
HISTCONTROL=
Teraz zdefiniuj funkcję do wywołania jako $PROMPT_COMMAND
:
isnewline () {
# read the last history number
prompt_command__isnewline__last="$prompt_command__isnewline__curr"
# get the current history number
prompt_command__isnewline__curr="$(history 1 | grep -oP '^\ +\K[0-9]+')"
[ "$prompt_command__isnewline__curr" = "$prompt_command__isnewline__last" ] && \
echo "User hit return"
}
Teraz ustaw $PROMPT_COMMAND
zmienną:
PROMPT_COMMAND="isnewline"
Zobacz wynik:
user@host:~$ true
user@host:~$ <return>
User hit return
user@host:~$ <space><return>
user@host:~$
last
jest zachowywana od jednego wywołania isnewline
do następnego (wybierz mniej ogólną nazwę, prompt_command__isnewline__last
aby uniknąć kolizji).
HISTCONTROL="" function last_was_blank { local last_command="$(history 1)" if [[ "$last_was_blank_PREVIOUS_LINE" = "$last_command" ]] ; then echo "true" else echo "false" fi export last_was_blank_PREVIOUS_LINE="$last_command" } PROMPT_COMMAND=last_was_blank
Nie wiem, jak to zrobić, per se . Ale możesz uzyskać ten sam efekt, używając
trap debugowanie komendy lub komendy
Spowoduje to, że some_command_or_function
zostanie wywołany za każdym razem, gdy uruchomisz polecenie. Trudne jest to, że nie zostanie wywołane, jeśli tylko uderzysz Enter- chyba że masz zdefiniowany PROMPT_COMMAND, w którym to przypadku naciśnięcie Enterwywołuje PROMPT_COMMAND, co z kolei wyzwala pułapkę.
Być może najprostszym sposobem na osiągnięcie pożądanego rezultatu jest zdefiniowanie funkcji pułapki debugowania zamiast używania PROMPT_COMMAND. Ale nie mogę powiedzieć, ponieważ nie wiem, jaki wynik chcesz. Jeśli chcesz, aby coś się wydarzyło po prostu po naciśnięciu Enter, a coś innego / dodatkowego wydarzy się po wpisaniu polecenia, to (AFAIK) musisz użyć pułapki debugowania i PROMPT_COMMAND. Zobacz tę odpowiedź i tę, aby dowiedzieć się, jak sprawić, by oba mechanizmy ładnie ze sobą grały.
(Byłby to komentarz do zaakceptowanej odpowiedzi, gdybym mógł dodawać komentarze ...) @schlimmen, możesz ustawić HISTTIMEFORMAT
coś takiego, HISTTIMEFORMAT='%F %T '
a następnie zapisać i porównać history 1
. Jest tak, ponieważ w przypadku skasowanych danych przynajmniej znacznik czasu (ewentualnie powtarzanego) ostatniego polecenia zmienia się za każdym razem --- i przy HISSTIMEFORMAT
odpowiednio ustawionym, history 1
wyświetli znacznik czasu (w przeciwieństwie do fc
), a zatem różni się nawet między powtarzanymi poleceniami.