powiedzieć, czy ostatnie polecenie było puste w PROMPT_COMMAND

12

Czy w bash od wewnątrz PROMPT_COMMAND istnieje sposób, aby stwierdzić, czy użytkownik po prostu nacisnął „return” i nie wprowadził polecenia?

użytkownik
źródło

Odpowiedzi:

7

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_COMMANDsię 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=ignoredupslub HISTCONTROL=erasedups), to błędnie zgłosi puste polecenie po uruchomieniu dwóch identycznych poleceń kolejno.

Gilles „SO- przestań być zły”
źródło
Dzięki, Gilles. Coś tu brakuje. Wydaje się, że to nigdy nie działa, ponieważ „echo hello” w pierwszym wierszu funkcji dosłownej nie działa, chociaż PROMPT_COMMAND = „echo hello” działa. Myślałem, że może to być problem HISTCMD_previous vs. HISTCMD_PREVIOUS, ale nie ma kości. Wciąż będę szturchać, ale komentuję, ponieważ twoje bash fu jest wyraźnie większe niż moje.
użytkownik
@ użytkownik Naprawiłem więcej literówek, w szczególności ${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ę.
Gilles „SO- przestań być zły”
1
To rozwiązanie opiera się na założeniu, że duplikaty są zapisywane w historii (co dla mnie jest wyłączone). Dlatego to rozwiązanie nie działa zgodnie z oczekiwaniami dla powtarzających się poleceń, podczas gdy duplikaty nie są zapisywane w historii.
schlimmchen
4

Istnieje obejście, ale ma pewne wymagania:

Musisz ustawić $HISTCONTROLzapisywanie 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_COMMANDzmienną:

PROMPT_COMMAND="isnewline"

Zobacz wynik:

user@host:~$ true
user@host:~$ <return>
User hit return
user@host:~$ <space><return>
user@host:~$ 
chaos
źródło
Nie rozumiem, dlaczego używasz tutaj pliku tymczasowego. Zmienna lastjest zachowywana od jednego wywołania isnewlinedo następnego (wybierz mniej ogólną nazwę, prompt_command__isnewline__lastaby uniknąć kolizji).
Gilles „SO- przestań być zły”
@Gilles Masz rację, zmieniłem to, dziękuję za twoją sugestię
chaos
Dzięki chaos. Użyłem tego samego pomysłu do następujących, które są nieco łatwiejsze do przeanalizowania. 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
użytkownik
1

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_functionzostanie 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źtę, aby dowiedzieć się, jak sprawić, by oba mechanizmy ładnie ze sobą grały.

Scott
źródło
0

(Byłby to komentarz do zaakceptowanej odpowiedzi, gdybym mógł dodawać komentarze ...) @schlimmen, możesz ustawić HISTTIMEFORMATcoś 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 HISSTIMEFORMATodpowiednio ustawionym, history 1wyświetli znacznik czasu (w przeciwieństwie do fc), a zatem różni się nawet między powtarzanymi poleceniami.

Pavel Smerk
źródło