Jak dołączyć polecenia do PS1 Basha bez obliczania długości linii podziału?

13

Tonin wskazał błąd w moim domyślnym pytaniu . Minimalny przykład:

  1. Ustaw PS1:

    PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " ")$ '

    W tym momencie monit wygląda następująco:

    $ 
  2. Teraz uruchom kod wyjściowy, uruchamiając:

    false

    Teraz monit zawiera kod wyjścia w kolorze czerwonym na początku wiersza:

    1 $ 
  3. Naciśnij Ctrl- r.
  4. Wpisz „false”. Teraz monit zawiera tylko wyszukiwanie:

    (reverse-i-search)`false': false
  5. Prasa Enter.

Wynikowa historia terminali zawiera teraz:

1 $ch)`false': false

Oczekiwany wynik:

1 $ false

Oznacza to, że wyniki wyszukiwania historii są pomieszane z pytaniem i ukrywają rzeczywiste polecenie, które zostało uruchomione.

Próbowałem obejść ten problem, używającPROMPT_COMMAND :

set_exit_code() {
    exit_code=$?
    [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " "
}
set_bash_prompt() {
    PS1='$(set_exit_code)$ ' # Double quotes give the same result
}
PROMPT_COMMAND=set_bash_prompt

To wydaje się nie działać - linia wygląda dokładnie tak samo jak przedtem po wyszukiwaniu i uruchomieniu.

Jak mogę to naprawić?

l0b0
źródło
1
Wydaje się, że jest to kontynuacja unix.stackexchange.com/a/71012
manatwork

Odpowiedzi:

8

Odpowiedź znalazłem na askubuntu.com . @qeirha wspomniał, że musisz powiedzieć bashowi, że sekwencja znaków nie powinna być liczona w długości monitu, a robisz to, dołączając ją \[ \]. Na podstawie podanego przykładu, oto jedno rozwiązanie:

red=$(tput setaf 1)

reset=$(tput sgr0)

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$red\] $exit_code \[$reset\] " ")$ '
Timothy Martin
źródło
Nie musisz iść do Zapytaj Ubuntu o to. Również tutaj mamy już dość odpowiedzi na to pytanie.
manatwork
Dziękujemy za radę @manatwork! Chciałem odpowiednio przypisać wyjaśnienie i podałem referencję jako uprzejmość.
Timothy Martin
Uznanie nie jest problemem. Ale kiedy mówimy o problemie: ukośniki odwrotne, które nie były ukrywane, znikały z Markdown, więc twój zwykły \ [stał się [w twoim poście, więc wyświetlany kod nie działał przez skopiowanie go do terminala. Można tego uniknąć, stosując kod wbudowany lub znaczniki bloku kodu. ( Jak sformatować swoje posty przy użyciu Markdown lub HTML? )
manatwork
1
Nie! Naprawiłem już ten sam problem z innym PS1kodem, dlaczego go nie widziałem?
l0b0,
1
PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$(tput setaf 1)\] $exit_code \[$(tput sgr0)\] " ")$ '

(Przepraszamy, brak tutaj wyjaśnień. Zobacz Jak prawidłowo dostosować PS1? Lub inne pytanie dotyczące problemów z szybkim obliczaniem długości i \[... \]).

manatwork
źródło
Do drugiego pytania @ l0b0 dodam to przy użyciu PS1 i \[...\]działa dobrze, o ile możesz umieścić cały kod, który chcesz wygenerować, w jednym ciągu. Jeśli jednak chcesz podzielić swój kod na małe funkcje, dochodzisz do punktu, w którym nie możesz umieścić nawiasów początkowych i końcowych w tym samym łańcuchu / funkcji. I to przerywa zawijanie linii. Chyba że użyjesz PROMPT_COMMANDdo ponownego obliczenia PS1przy każdym monicie.
Tonin,
1

Rozwijając odpowiedź @manatwork, ale utrzymując kod dzielący PS1obliczenia na różne funkcje, możesz napisać swój monit w następujący sposób:

set_exit_code() {
    exit_code=$?
    [[ $exit_code -eq 0 ]] || printf "\[$(tput setaf 1)\] $exit_code \[$(tput sgr0)\] "
}
set_bash_prompt() {
    PS1="$(set_exit_code)$ " # with double quotes!
}
PROMPT_COMMAND=set_bash_prompt

Podwójne cudzysłowy są obowiązkowe zarówno podczas ustawiania, jak PS1i używania printfw funkcji.

Tonin
źródło
Do przyszłego wykorzystania użyj funkcji bash w swoim .bashrc- nie umieszczaj kodu w osobnym pliku i nie wywołuj tego.
starbeamrainbowlabs