Vous utilisez des variables pour stocker les codes de couleur de terminal pour PS1?

33

Dans mon cas .bashrc, j’utilise les codes de couleur du terminal ANSI pour colorier divers bits. Cela ressemble à ceci:

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

virtual_envet git_branchsont des fonctions bash qui génèrent des choses sur stdout.

Maintenant, pour faciliter la lecture et la modification, j'aimerais stocker les codes de couleur dans des variables et les référencer, au lieu de les incorporer directement dans PS1. J'ai donc un tas de variables comme celle-ci:

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

J'aimerais pouvoir écrire quelque chose comme:

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

Mais cela ne fonctionne pas - les codes de couleur apparaissent dans l'invite, comme s'ils étaient échappés. Les couleurs fonctionnent correctement si j'utilise des guillemets doubles à la place PS1, mais l'invite ne change que lorsque je le fais source ~/.bashrc.

J'ai essayé d'autres choses que j'ai déjà vues faire: utiliser printf, utiliser des guillemets simples pour les couleurs, insérer la variable \[and \]dans PS1au lieu de la variable color, mais rien ne semble fonctionner.

Comment puis-je utiliser des variables pour les codes de couleur?

Ismail Badawi
la source
Pouvez-vous nous donner votre .bashrc?
jeudi
@cuonglm Tous vos .bashrc sont nous appartiennent? Je vais me montrer.
CivFan

Réponses:

20

La solution consiste à demander au shell de substituer les variables de couleur lors de la définition de l'invite, mais pas les fonctions. Pour ce faire, utilisez les guillemets tels que vous les avez essayés à l'origine, mais échappez les commandes afin qu'elles ne soient pas évaluées jusqu'à ce que l'invite soit dessinée.

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

Notez le \avant le $()sur chaque commande.

Si nous en faisons écho, nous voyons:

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

Comme vous pouvez le constater, les variables de couleur ont été substituées, mais pas les commandes.

Patrick
la source
1
Cela ne semble pas fonctionner si $ (git_branch) essaye également d'imprimer en utilisant $ {YELLOW} etc. Dans cette section seulement, vous aurez toujours tous les caractères [].
WB Reed
7

Le problème est que votre variable GREENcontient la chaîne littérale consistant en "barre oblique inverse barre oblique inverse trois trois" et ainsi de suite. Il ne contient par exemple pas le caractère d'échappement ASCII requis pour que votre terminal change de couleur.

Vous pouvez insérer manuellement les caractères de contrôle GREEN(et YELLOWet RESET), mais une meilleure option consiste à les utiliser tputen premier lieu pour éviter de coder en dur et de prendre en charge tous les types de terminaux.

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

La raison pour laquelle ce monde quand vous mettez « backslash zéro trois trois » etc ... directement dans PS1est que l' interprétation de certaines séquences de Backslash est une caractéristique d'inciter de bash (voir la section PRÉCISIONS dans le manuel. Cette substitution se produit avant l' expansion des paramètres, la commande La substitution, l’expansion arithmétique et la suppression des devis, cependant, ne sont donc pas appliqués aux résultats de toutes ces autres opérations.

Celada
la source
5
Lorsque vous procédez ainsi, vous devez insérer les variables de couleur dans \[\]le $PS1. Par exemple: PS1='\u@\h:\w\[${YELLOW}\]'. Si vous ne le faites pas et que vous vous retrouvez avec une longue commande qui passe à la ligne suivante, vous rencontrerez toutes sortes de problèmes. Le shell utilise le \[\]pour déterminer les caractères non imprimables. Il ne les prend donc pas en compte dans le calcul de la longueur de l'invite. Il en a besoin pour tracer correctement la ligne lorsqu'elle dépasse la largeur du terminal.
Patrick
Je ne savais pas tput, merci. J'utiliserai la réponse de Patrick pour l'instant mais je reviendrai là-dessus quand j'en aurai l'occasion.
Ismail Badawi
2

Changez la façon dont vous remplissez $ GREEN, $ YELLOW et $ 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
la source
1
Cela fait exactement la même chose que la réponse de Celada. Mais Celada est plus portable au cas où le terminal utilise des codes d'échappement différents pour le réglage des couleurs. Il y aura également le même problème avec l'invite multiligne.
Patrick
2
Le \[…\]bit doit rester dans l'invite, vous ne pouvez pas le fourrer dans une variable. Vous l'avez complètement supprimé, ce qui entraînera des problèmes d'affichage (le curseur ne se trouve pas à la position où bash l'attend).
Gilles 'SO- arrête d'être méchant'
Outre les préoccupations de @Patrick, echo -e n'est pas portable.
helpermethod
1
La non-portabilité s'accompagne de davantage de fonctionnalités - vous tput setafne pouvez pas choisir parmi les couleurs "claires", telles que le cyan clair. La réponse de Cyrus, cependant, fait.
CivFan