Come includere comandi nella PS1 di Bash senza interrompere il calcolo della lunghezza della linea?


13

Tonin ha segnalato un errore nel mio prompt predefinito . Esempio minimo:

  1. Imposta PS1:

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

    A questo punto, il prompt è simile al seguente:

    $ 
  2. Ora attiva l'output del codice di uscita eseguendo:

    false

    Ora il prompt contiene il codice di uscita in rosso all'inizio della riga:

    1 $ 
  3. Premere Ctrl- r.
  4. Digita "false". Ora il prompt contiene solo la ricerca:

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

La cronologia dei terminali risultante ora contiene quanto segue:

1 $ch)`false': false

Uscita prevista:

1 $ false

Cioè, sembra che l'output della ricerca della cronologia sia mescolato con il prompt e che nasconda il comando effettivo che è stato eseguito.

Ho provato a aggirare questo usandoPROMPT_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

Questo non sembra funzionare - la linea sembra esattamente la stessa di prima dopo la ricerca e l'esecuzione.

Come posso risolvere questo problema?


1
Questa sembra essere la continuazione di unix.stackexchange.com/a/71012
manatwork

Risposte:


8

Ho trovato la risposta su askubuntu.com . @qeirha ha detto che devi dire a bash che la sequenza di caratteri non deve essere contata nella lunghezza del prompt, e lo fai racchiudendola \[ \]. Sulla base dell'esempio fornito, ecco una soluzione:

red=$(tput setaf 1)

reset=$(tput sgr0)

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$red\] $exit_code \[$reset\] " ")$ '

Non c'è bisogno di andare a chiedere Ubuntu per questo. Abbiamo già abbastanza risposte a questa domanda anche qui.
arte

Grazie per il consiglio @manatwork! Volevo dare il giusto credito per la spiegazione e ho fornito il riferimento come cortesia.
Timothy Martin,

Dare credito non è un problema. Ma mentre parliamo di problema: le barre rovesciate senza caratteri di escape svanivano da Markdown, quindi il tuo semplice [[divenne [nel tuo post, quindi il codice visualizzato non funzionava copiandolo e incollandolo nel terminale. Ciò può essere evitato utilizzando il codice inline o il markup del blocco di codice. ( Come posso formattare i miei post usando Markdown o HTML? )
manatwork

1
D'oh! Ho già risolto lo stesso problema con altri PS1codici, perché non l'ho visto?
l0b0

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

(Siamo spiacenti, nessuna spiegazione qui. Vedi Come personalizzare correttamente PS1? O qualsiasi altra domanda sui problemi di calcolo della lunghezza del prompt e \[... \]).


Alla seconda domanda @ l0b0, aggiungerò che usando PS1 e \[...\]funziona benissimo finché puoi mettere tutto il codice che vuoi generare il tuo prompt in una singola stringa. Tuttavia, se si desidera dividere il codice in piccole funzioni, si arriva a un punto in cui non è possibile inserire le parentesi iniziali e finali nella stessa stringa / funzione. E questo si interrompe. A meno che tu non ricorra all'uso PROMPT_COMMANDper ricalcolare il tuo PS1ad ogni prompt.
Tonin,

1

Espandendo la risposta di @manatwork ma mantenendo il codice che divide il PS1calcolo in diverse funzioni, è possibile scrivere il prompt nel modo seguente:

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

Le virgolette doppie sono obbligatorie sia durante l'impostazione PS1che durante l'uso printfnella funzione.


Per riferimento futuro, usa una funzione bash nel tuo .bashrc- non mettere il codice in un file separato e chiamalo.
Starbeamrainbowlabs
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.