web-dev-qa-db-fra.com

bash Invite et répète les couleurs dans une fonction

J'ai ceci dans mon .bashrc:

LIGHTGREEN="\[\033[1;32m\]"
LIGHTRED="\[\033[1;31m\]"
WHITE="\[\033[0;37m\]"
RESET="\[\033[0;00m\]"

function error_test {
    if [[ $? = "0" ]]; then
        echo -e "$LIGHTGREEN"
    else
        echo -e "$LIGHTRED"
    fi
}

PS1="\u\$(error_test)@\w$RESET \$ "

Cela semble rendre la sortie du shell exactement:

username\[\]@~/

Les échappements [et] autour des codes de couleur apparaissent dans mon invite. Si je supprime les codes d'échappement autour des couleurs, cela fonctionne, mais le retour à la ligne bash échoue incroyablement. 

Notez que si PS1="LIGHTGREEN - whatever - $RESET" cela fonctionne et que les [et] ne sont pas échappés. Cependant, je veux faire cela dans une fonction, ce qui semble être le problème.

Je ne trouve pas de bonne documentation à ce sujet. man echo ne liste même pas une option -e. Bash semble posséder beaucoup de connaissances documentées et non documentées.

42
Andy Ray

J'ai trouvé ce sujet à la recherche de réponses sur la définition de la couleur bash avec l'échappement de \[ \] depuis la fonction bash.

En fait, il y a une solution. Bash permet de générer l'invite PS1 chaque fois que l'invite est rendue. 

set_bash_Prompt(){
    PS1="\u@\h $(call_your_function) $>"
}

Prompt_COMMAND=set_bash_Prompt

De cette façon, PS1 sera interprété à chaque fois que Invite sera affichée. Elle appellera donc function et restituera correctement toutes les séquences d'échappement, y compris \[ \], qui sont importantes pour compter la longueur de Prompt (par exemple, pour que l'historique des commandes fonctionne correctement).

J'espère que cela aidera quelqu'un, car je passe une demi-journée à résoudre ce problème.

48
thedk

Utilisez \001 au lieu de \[ et \002 au lieu de \] et soyez conscient des conséquences de l’utilisation dePrompt_COMMAND car cette méthode réinitialisera l’invite à chaque fois (ce qui peut également correspondre à vos souhaits).

La solution pour bash Prompt faisant écho aux couleurs d’une fonction est expliquée here :

Les \[\] ne sont spéciaux que lorsque vous attribuez PS1. Si vous les imprimez Dans une fonction qui s'exécute lorsque l'invite est affichée, cela ne fonctionne pas . Dans ce cas, vous devez utiliser les octets \001 et \002.

Il y a aussi cette autre réponse qui pointe dans la même direction:

\[ et \] spécifiques à Bash sont en fait traduits en \001 et \002

Définir PS1 dans une fonction appelée par Prompt_COMMAND comme suggéré dans l'option acceptée, réinitialise PS1 à chaque fois, ce qui empêche les autres scripts de modifier facilement votre promtp (par exemple, Python virtualnenv activate.sh ):

$ echo $PS1
<your PS1>
$ PS1="(TEST)$PS1"
$ echo $PS1
<(TEST) is not prepended to PS1 if you are using Prompt_COMMAND as it is reset>
22
archemiro

\[ et \] doivent être utilisés directement dans $PS*, plutôt que de simplement les sortir via echo.

LIGHTGREEN="\033[1;32m"
LIGHTRED="\033[1;31m"
WHITE="\033[0;37m"
RESET="\033[0;00m"

function error_test {
    if [[ $? = "0" ]]; then
        echo -e "$LIGHTGREEN"
    else
        echo -e "$LIGHTRED"
    fi
}

PS1="\u\[\$(error_test)\]@\w\[$RESET\] \$ "
7

Voici la partie colorée du code de sortie de mon PS1 code :

color_enabled() {
    local -i colors=$(tput colors 2>/dev/null)
    [[ $? -eq 0 ]] && [[ $colors -gt 2 ]]
}

BOLD_FORMAT="${BOLD_FORMAT-$(color_enabled && tput bold)}"
ERROR_FORMAT="${ERROR_FORMAT-$(color_enabled && tput setaf 1)}"
RESET_FORMAT="${RESET_FORMAT-$(color_enabled && tput sgr0)}"

# Exit code
PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s $BOLD_FORMAT $ERROR_FORMAT $exit_code $RESET_FORMAT " ")'

Capture d'écran (avec un chemin d'accès au référentiel Subversion anonymisé): Color coded output

0
l0b0

Cela fonctionnera bien.

LIGHTGREEN="\e[32m"
LIGHTRED="\e[31m"
RESET="\e[0m"

error_test () {
    if [[ $? = "0" ]]; then
        echo -e "$LIGHTGREEN"
    else
        echo -e "$LIGHTRED"
    fi
}
export PS1=$(printf "$(error_test) $(whoami)@${RESET}$(pwd) ")
0
Luis Lavaire

Je réalise que c'est un sujet ancien, mais je viens de travailler avec des fonctions. L'astuce consiste à séparer les parties imprimantes et non imprimantes de la fonction pour pouvoir fixer correctement les parties non imprimables à l'aide de []. Normalement, j'aime que ma ligne ERROR .. soit séparée (et que ce n'est pas un problème pour le moment), mais cela fonctionne également correctement si tout est sur une seule ligne.

Notez que je retourne le $ précédent? valeur de chaque sous-shell donc $? se propage de l'un à l'autre.

PS1="\n\
\[\`
  cja_prv_retval=\$?;
  if [ \$cja_prv_retval != 0 ];
     then echo -ne \$E_ERROR;
  fi
  exit \$cja_prv_retval
\`\]\
\`
  cja_prv_retval=\$?;
  if [ \$cja_prv_retval != 0 ];
     then echo -ne \"ERROR: RETURN CODE \$cja_prv_retval\";
  fi
  exit \$cja_prv_retval
\`\
\[\`
  cja_prv_retval=\$?;
  if [ \$cja_prv_retval != 0 ];
     then echo -ne \$E_RESET;
  fi
  exit \$cja_prv_retval
\`\]\
${P_RESET}${P_GRAY}\! \t ${P_RED}\u${P_GRAY}@${P_GREEN}\h ${P_YELLOW}\w ${P_CYAN}   ══>${P_RESET} "

Cela me donne non plus

2021 12:28:05 cja@morpheus04 ~ ══>

s'il n'y a pas d'erreur, ou

ERROR: RETURN CODE 1 2021 12:28:16 cja@morpheus04 ~ ══>

s'il y a une erreur. Tout est correctement espacé (l'édition d'historique multiligne fonctionne correctement).

0
ChrisAshton84