Échapper des caractères non imprimables dans une fonction pour une invite Bash

22

Dans une invite Bash (variable PS1), j'appelle une fonction pour potentiellement ajouter du texte à l'invite: export PS1="\u@\h \$(my_function) \$ "

Cependant, la fonction dans l'invite contient des codes de couleur ANSI qui changent en fonction de la sortie de la fonction (parfois rouge, parfois verte). L'ajout de " \[" à la variable PS1 devrait échapper à ces codes en tant que non-impression, mais si je fais un echodans la fonction, le " \[" s'imprime littéralement dans l'invite.

Comment puis-je échapper ces codes de couleur ANSI depuis une fonction pour les utiliser dans une invite bash?

MinuitLightning
la source

Réponses:

34

La bibliothèque readline accepte \001et \002(ASCII SOH et STX ) comme délimiteurs de texte non imprimables. Ceux-ci fonctionnent également dans n'importe quelle application qui utilise readline .

De lib/readline/display.c:243en bash code source:

243 /* Current implementation:
244         \001 (^A) start non-visible characters
245         \002 (^B) end non-visible characters
246    all characters except \001 and \002 (following a \001) are copied to
247    the returned string; all characters except those between \001 and
248    \002 are assumed to be `visible'. */

Les spécificités de bash\[ et \]sont en fait traduites de \001et \002vers y.tab.c:7640.


Remarque: Si vous utilisez bash ou printfou echo -e, et si votre texte a \001ou \002immédiatement avant un nombre, vous rencontrerez un bogue bash qui le fait manger un chiffre de trop lors du traitement des échappements octaux - c'est-à-dire, \00142sera interprété comme octal 014 (suivi de ASCII "2"), au lieu de l'octal correct 01 (suivi de ASCII "42"). Pour cette raison, utilisez plutôt des versions hexadécimales \x01et \x02.

grawity
la source
Ça le fait! echo -e "\001\e[31m\002RED"fonctionne comme prévu. Merci!
MidnightLightning
Désolé de ressusciter une réponse, mais quel est l'équivalent sur dash / ash / sh?
Hosh Sadiq
@Hosh S'ils utilisent readline, \001et \002fonctionneront. Sinon, je ne suis pas sûr. Dash, par exemple, n'utilise certainement pas readline .
wjandrea
1

Voici une belle réponse complète. J'ai dû faire beaucoup plus de recherches pour savoir où le \ 001 etc. devait aller. J'espère que cela t'aides.

# Color prompt for git
reset=$(tput sgr0)
boldgreen=$(tput setaf 2)$(tput bold)
cyan=$(tput sgr0)$(tput setaf 6)
boldred=$(tput setaf 1)$(tput bold)
boldwhite=$(tput setaf 7)$(tput bold)
boldyellow=$(tput setaf 3)$(tput bold)

PARENCLR=$'\001\e[0;36m\002'
BRANCHCLR=$'\001\e[1;33m\002'

alias branchname="git branch 2>/dev/null | grep '*' | sed 's/* \(.*\)/ ${PARENCLR}(${BRANCHCLR}\1${PARENCLR}\)/'"

GIT_STATUS='$(branchname)'

PROMPT_CHAR="\$"
PS1="\[$boldgreen\]\u\[$cyan\]::\[$boldred\]\h \[$cyan\]{\[$boldwhite\].../\W\[$cyan\]}\[$reset\]$GIT_STATUS\[$reset\]$PROMPT_CHAR "

De la façon dont je l'ai configuré ici, les parenthèses de la branche git n'apparaissent que si vous êtes dans une branche git, sinon c'est vide.

Dan L
la source
0

Sur la base de la réponse de grawity , les éléments suivants incluront les séquences de contrôle ANSI en ASCII SOH( ^A) et STX( ^B) qui sont équivalentes \[et \]respectivement:

function readline_ANSI_escape() {
  if [[ $# -ge 1 ]]; then
    echo "$*"
  else
    cat  # Read string from STDIN
  fi | \
  perl -pe 's/(?:(?<!\x1)|(?<!\\\[))(\x1b\[[0-9;]*[mG])(?!\x2|\\\])/\x1\1\x2/g'
}

Utilisez-le comme:

$ echo $'\e[0;1;31mRED' | readline_ANSI_escape

Ou:

$ readline_ANSI_escape "$string"

En prime, l'exécution de la fonction plusieurs fois ne rééchappera pas aux codes de contrôle déjà échappés.

Tom Hale
la source
-2

Si vous souhaitez les utiliser dans l'invite, vous devez effectuer la \[. Mais si vous voulez l'utiliser dans un écho, vous devez utiliser \033[.

Wuffers
la source
Hmmm ... Ajout de \ 033 [avant la commande ANSI ("\ e [31m") et \ 033] après qu'il semble que le caractère imprimé suivant dans l'invite ne s'imprime pas.
MidnightLightning
1
Vous ne voulez pas faire \ 033] après cela. \ 033 [31m démarre la couleur, après quoi vous devez la restaurer avec \ 033 [0m
Wuffers