Usando variáveis ​​para armazenar códigos de cores de terminal para PS1?

33

No meu .bashrc, uso códigos de cores do terminal ANSI para colorir vários bits. Se parece com isso:

PS1='\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ '

onde virtual_enve git_branchsão funções bash que produzem coisas no stdout.

Agora, para facilitar a leitura e a modificação, eu gostaria de armazenar os códigos de cores nas variáveis ​​e consultá-las, em vez de incorporá-las diretamente PS1. Então, eu tenho um monte de variáveis ​​como esta:

GREEN="\[\033[32m\]"
YELLOW="\[\033[33m\]"
RESET="\[\033[0m\]"

Eu gostaria de poder escrever algo como:

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '

Mas isso não funciona - os códigos de cores aparecem no prompt, como se tivessem escapado. As cores funcionarão corretamente se eu usar aspas duplas em vez disso PS1, mas o prompt somente será alterado quando o fizer source ~/.bashrc.

Eu tentei outras coisas que vi pessoas fazerem - usando printf, usando aspas simples para as cores, colocando a variável in \[e \]ao PS1invés da variável de cor, mas nada parece funcionar.

Como posso usar variáveis ​​para os códigos de cores?

Ismail Badawi
fonte
Você pode nos dar o seu .bashrc?
18714 cu Cullm
@cuonglm Todos os seus .bashrc pertencem a nós? Eu vou me mostrar.
CivFan

Respostas:

20

A solução é fazer com que o shell substitua as variáveis ​​de cor ao definir o prompt, mas não as funções. Para fazer isso, use aspas duplas como você havia tentado originalmente, mas escape dos comandos para que não sejam avaliados até que o prompt seja desenhado.

PS1="\u@\h:\w${YELLOW}\$(virtual_env)${GREEN}\$(git_branch)${RESET}$ "

Observe o \ antes do $()em cada comando.

Se ecoarmos isso, vemos:

echo "$PS1"
\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ 

Como você pode ver, as variáveis ​​de cores foram substituídas, mas não os comandos.

Patrick
fonte
1
Isso não parece funcionar se $ (git_branch) também estiver tentando imprimir usando $ {YELLOW} etc. Somente nessa seção, você ainda terá todos os caracteres [].
WB Reed
7

O problema é que sua variável GREENcontém a cadeia literal que consiste em "barra invertida barra invertida zero três três" e assim por diante. Ele não contém, por exemplo, um caractere de escape ASCII, conforme necessário, para que o terminal mude de cor.

Você pode colocar caracteres de controle em GREEN(e YELLOWe RESET) manualmente, mas uma opção muito melhor é usar tputem primeiro lugar para que você não precise codificar nada e suporte qualquer tipo de terminal.

GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
RESET="$(tput setaf 0)"

A razão pela qual o mundo quando você coloca "barra invertida zero três três" etc ... diretamente PS1é que a interpretação de certas seqüências de barra invertida é um recurso do prompt do bash (consulte a seção PROMPTING no manual. Esta substituição ocorre antes da expansão do parâmetro, comando substituição, expansão aritmética e remoção de cotação, portanto, não é aplicada aos resultados de todas as outras operações.

Celada
fonte
5
Ao fazer isso dessa maneira, você precisa agrupar as variáveis ​​de cores \[\]dentro do $PS1. Por exemplo: PS1='\u@\h:\w\[${YELLOW}\]'. Se você não fizer isso e acabar com um comando longo que passa para a próxima linha, encontrará todos os tipos de problemas. O shell usa o \[\]para determinar quais caracteres não são imprimíveis, portanto, não os fatoram no cálculo do tamanho do prompt. Ele precisa disso para que possa desenhar corretamente a linha quando exceder a largura do terminal.
317 Patrick Patrick
Eu não sabia tput, obrigado. Vou usar a resposta de Patrick por enquanto, mas revisitarei isso quando tiver uma chance.
Ismail Badawi
2

Mude a maneira como você preenche $ VERDE, $ AMARELO e $ RESET:

GREEN="$(echo -e "\033[32m")"
YELLOW="$(echo -e "\033[33m")"
RESET="$(echo -e "\033[0m")"

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '
Cyrus
fonte
1
Isso, na verdade, faz exatamente a mesma coisa que a resposta de Celada. Mas o Celada é mais portátil, caso o terminal use códigos de escape diferentes para a configuração de cores. Também terá o mesmo problema com o prompt de várias linhas.
317 Patrick Patrick
2
O \[…\]bit precisa permanecer no prompt, você não pode colocá-lo em uma variável. Você o removeu completamente, o que resultará em problemas de exibição (o cursor não estará na posição em que o bash espera).
Gilles 'SO- stop be evil'
Além das preocupações com @Patrick, o echo -e não é portátil.
Helpermethod
1
Com a não portabilidade, surgem mais recursos - tput setafnão permite escolher entre o conjunto de cores "claras", como o ciano claro. @ A resposta de Cyrus, no entanto, sim.
CivFan