Depois de resolver o primeiro problema com meu prompt personalizado, ainda tenho outro.
Quando eu percorro meus últimos comandos usados por meio das teclas de seta para cima e para baixo, às vezes alguns caracteres de um comando anterior permanecem visíveis, embora não estejam acessíveis nem estejam realmente na linha de comando. Eles são apenas um bug visual muito chato e confuso.
Aqui subi um pouco no histórico de comandos e depois voltei ao prompt atual (vazio) e digitei echo
. o pip i
(vindo de um pip install
comando anterior) não está acessível com meu cursor. É visível lá, mas na verdade não existe.
Meu .bashrc
tem este código para personalizar o prompt:
set_PS1()
{
local Reset="\\[$(tput sgr0 )\\]"
local Bold="\\[$(tput bold )\\]"
local Red="\\[$(tput setaf 1 )\\]"
local Green="\\[$(tput setaf 2 )\\]"
local Yellow="\\[$(tput setaf 3 )\\]"
local Blue="\\[$(tput setaf 4 )\\]"
local MagentaBG="\\[$(tput setab 5 )\\]"
local Cyan="\\[$(tput setaf 6 )\\]"
local Whoami='\u'
local Where='\w'
local Hostname='\h'
local Time='\D{%H:%M:%S}'
local Exit_Code="$?"
exit_code_prompt() {
local Exit_Code="$?"
local Red="$(tput setaf 1 )"
local Green="$(tput setaf 2 )"
if (($Exit_Code == 0 )); then
printf '%s\xE2\x9C\x93 \xE2\x86\x92 ' "$Green" # Green checkmark symbol
else
printf '%s\xE2\x9C\x98 %s \xE2\x86\x92 ' "$Red" "$Exit_Code" # Red cross mark symbol and exit code
fi
}
local Line_1="$Bold$Yellow$Time $Cyan$Whoami$Blue@$Cyan$Hostname$Reset$Bold":" $Blue$Where$Reset"
local Line_2="$Bold\$(exit_code_prompt)$Reset$Bold \$: $Reset"
#local Line_2="$Bold \$: $Reset"
PS1="$Line_1\n$Line_2"
unset -f set_PS1
}
set_PS1
Já reduzi o problema à exit_code_prompt
função, pois o problema não aparece se eu removê-lo do$Line_2
EDIT: Quando coloco as definições de cores dentro da função entre colchetes, como na parte externa, assim:
exit_code_prompt() {
local Exit_Code="$?"
local Red="\\[$(tput setaf 1 )\\]"
local Green="\\[$(tput setaf 2 )\\]"
if (($Exit_Code == 0 )); then
printf '%s\xE2\x9C\x93 \xE2\x86\x92 ' "$Green" # Green checkmark symbol
else
printf '%s\xE2\x9C\x98 %s \xE2\x86\x92 ' "$Red" "$Exit_Code" # Red cross mark symbol and exit code
fi
}
Eu obtenho este resultado:
O mesmo resultado se eu colocar apenas barras invertidas. \
Além disso, o problema inicial ainda está lá!
Nova solução
Acontece que é realmente possível fazer isso com just
PS1
e notPROMPT_COMMAND
. Não precisamos definir nenhuma variável global adicional. Aqui está uma frase:PS1=$'\e[1;33m\\t \e[36m\u\e[34m@\e[36m\h\e[;1m: \e[34m\w\n \[\b\e[;1;31m✘\] ${?/#0/\[\b\b\e[32m✓ \]}${?/#[1-9]*/ }\[\b→\e[;1m\] \$: \[\e[m\]'
As melhorias da minha solução original abaixo são as seguintes:
\[\]
tput
para\e[...m
. Isso é compatível com o Ubuntu e não é uma preocupação porque a cor padrão.bashrc
também faz isso\e[Xm\e[Ym
em\e[X;Ym
, e o negrito anterior nem sempre precisa ser redefinido\D{%H:%M:%S}
=\\t
\X
não precisam de escape de barra invertida$?
ser0
ou positivo sem zeros à esquerda:?/#0*/
=?/#0/
${?/#[1-9]*/ }\[\b
insere um espaço, depois qualquer caractere (atualmente espaço) para diferente de zero e qualquer caractere (atualmente 0) para zero. Em seguida, o caractere adicional é excluído, para implementar a inserção de exatamente um espaço apenas para valores diferentes de zero.[1-9]*
é um glob que significa qualquer dígito de 1 a 9 e qualquer coisa, não um RegEx que significa qualquer número do anterior✘\] ${?/#0/\[\b\b\e[32m✓ \]}
sempre imprime primeiro o símbolo da cruz vermelha. Se for zero, voltamos e substituímos por uma marca de seleção verde. Se for diferente de zero, imprimiremos o código de erroSolução guiada
Aqui está um prompt de trabalho:
PS1
sofre expansão imediata e depois substituição, então precisamosPROMPT_COMMAND
set_PS1
global, mas você jáexit_code_prompt
vazou o global"\$"
precisa ser"\\$"
assim, passa por avaliação imediata em vez de imediatamenteprintf
é desnecessariamente complicado quando você poderia simplesmente fazer$''
Agora ↑/ ↓o histórico de comandos funciona. Rolar um prompt multilinha com Ctrl+ ←/ →também salta para a posição correta agora.
aqui estão alguns exemplos:
Demonstração imediata:
Sequência longa:
String longa então Ctrl+ ←:
pip install
entãoecho
:echo
então ↑na história: