Ma Konsole prend des couleurs
Type de script : Fonctions Bash, Bin Bash, (un peu comme Bond, James Bond)
Compatible: Bash on va dire :aie:
Prérequis: à mettre dans un fichier shebangué et à sourcer
Rien de stupéfiant, juste un peu de couleurs dans la Konsole quand un script raconte quelque chose:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
# renvoie le code couleur correspondant à une couleur en toutes lettres
get_color (){
OPTIND=1
while getopts :r:i: opt; do
case $opt in
r) # regular color, foreground de 30 à 37 - background de 40 à 47
case "$OPTARG" in
black|noir) test "$f" = true && return 30 ; test "$b" = true && return 40 ;;
red|rouge) test "$f" = true && return 31 ; test "$b" = true && return 41 ;;
green|vert) test "$f" = true && return 32 ; test "$b" = true && return 42 ;;
yellow|jaune) test "$f" = true && return 33 ; test "$b" = true && return 43 ;;
blue|bleu) test "$f" = true && return 34 ; test "$b" = true && return 44 ;;
purple|violet) test "$f" = true && return 35 ; test "$b" = true && return 45 ;;
cyan) test "$f" = true && return 36 ; test "$b" = true && return 46 ;;
white|blanc) test "$f" = true && return 37 ; test "$b" = true && return 47 ;;
*) echo "cas non géré get_color: $OPTARG ? f:$f ? b:$b ?" >&2 ;;
esac
;;
i) # highintensivity color (bof), foreground de 90 à 97 - background de 100 à 107
#~ echo "get_color opt: $opt" >&2
case "$OPTARG" in
black|noir) test "$F" = true && return 90 ; test "$B" = true && return 100 ;;
red|rouge) test "$F" = true && return 91 ; test "$B" = true && return 101 ;;
green|vert) test "$F" = true && return 92 ; test "$B" = true && return 102 ;;
yellow|jaune) test "$F" = true && return 93 ; test "$B" = true && return 103 ;;
blue|bleu) test "$F" = true && return 94 ; test "$B" = true && return 104 ;;
purple|violet) test "$F" = true && return 95 ; test "$B" = true && return 105 ;;
cyan) test "$F" = true && return 96 ; test "$B" = true && return 106 ;;
white|blanc) test "$F" = true && return 97 ; test "$B" = true && return 107 ;;
*) echo "cas non géré get_color: $OPTARG ? f:$f ? b:$b ?" >&2
;;
esac
;;
*) echo "cas '$opt' non géré par get_color" >&2
;;
esac
done
shift $((OPTIND - 1))
return 0
}
printc (){
deb='\e[' ; fin='\e[m' ; colsize= ; coltamp= ; k= ; args= ; strc=
OPTIND=1
while getopts :c:f:b:F:B:hn opt; do
case $opt in
c)
ansi_code="$OPTARG"
;;
f|F)
if [ "$opt" == "f" ]; then
f=true ; fc="$OPTARG"
else
F=true ; Fc="$OPTARG"
fi
;;
b|B)
if [ "$opt" == "b" ]; then b=true ; bc="$OPTARG"; else B=true ; Bc="$OPTARG"; fi
;;
h)
echo "printc [-c code_ansi] [f|F nom_couleur] [b|B nom_couleur] [--col INT] CHAÎNE" >&2
return 1
;; # --help
n) n=true ;; # sans retour à la ligne
*) # gestion des options longues, j'ai besoin de par exemple --col pour définir une longueur de colonne
k="$(eval echo \$$OPTIND)"
case "$k" in
--col) # la largeur de la colonne en nombre de caractère
# echo "shift 1, args:'$@'" >&2
colsize=$(eval echo \$$((OPTIND+1))) # suppose que le paramètre de l'option longue ne soit pas accolé
args="$@" ; args="${args#*$colsize }" # cherche les paramètres restants après le traitement de '--col val'
# double [[ ou génère des erreurs car $args contient des choses style '--' ça passe pas du tout en simple [
while [[ "$args" != "$@" ]]; do
# echo "while avant shift: /$@/" >&2
shift; done # shift tout ce qui se trouve avant , y compris '--col val' car
#echo "en sortie de while shift: /$@/" >&2
# géré par getopts options courtes et les options+val précédant '--col val' sont toujours présentes dans $@
# va sortir, suppose qu'on passe --col en dernière option avant la chaîne à imprimer.
;;
-) continue ;;
*)
echo "cas '$opt' non géré dans printc, try printc -h how-to" >&2
;;
esac
;;
esac
done
if [[ $colsize = +([0-9]) ]]; then
# la chaîne est l'ensemble des arguments restants "$@"
coltamp="$@" ; tampsize="${#coltamp}"
dif=$(($colsize - $tampsize))
case "$dif" in
[1-9]*) while [ "$dif" -gt 0 ]; do coltamp+=" " ; ((dif--)); done ;;
-[1-9]*) while [ "$dif" -lt 0 ]; do coltamp="${coltamp:1} " ; ((dif++)); done ;;
*) coltamp="" ;;
esac
else
shift $((OPTIND - 1)) # revient à shifter 2 pour sortir de boucle (l'opt traitée + son argument) si plus rien après
# ça merde cette ligne à mon avis, ça devrait pas se trouver là, mais c'est lié à la gestion par getopts (???)
coltamp="$@"
fi
# echo -e "sortie de getopts, args:'$args', \$$@:/$@/, colsize:$colsize" >&2
# Initialise la ligne avec les codes ansi : 0 1 2 3 4 5 7 pour normal bold atténué italic souligné clignotant reverse-v
strc="$ansi_code"
for c in f b F B; do
case "$c" in
f)
test "$f" = true || continue # ne s'arrête pas si pas de foreground regular
if [ -z "$strc" ]; then strc="$(get_color -r "$fc" ; echo $?)"
else strc+=";$(get_color -r "$fc" ; echo $?)"
fi ; F=false; f=false # foreground color (regular) traitée
;;
F)
test "$F" = true || continue # ne s'arrête pas si pas de foreground highintensivity
if [ -z "$strc" ]; then strc="$(get_color -i "$Fc" ; echo $?)"
else strc+=";$(get_color -i "$Fc" ; echo $?)"
fi ; F=false; f=false # foreground color (highintensivity) traitée
;;
b)
test "$b" = true || continue # idem pour les backgrounds regular ou intensivity
if [ -z "$strc" ]; then strc="$(get_color -r "$bc" ; echo $?)"
else strc+=";$(get_color -r "$bc" ; echo $?)"
fi ; B=false; b=false # background color (regular) traitée
;;
B)
test "$B" = true || continue
if [ -z "$strc" ]; then strc="$(get_color -i "$Bc" ; echo $?)"
else strc+=";$(get_color -i "$Bc" ; echo $?)"
fi ; B=false; b=false # background color (regular) traitée
;;
esac
done
if [ -z "$strc" ]; then
strc="${coltamp}"
else
strc="$deb${strc}m${coltamp}$fin"
fi
# echo "strc retour: '$strc'"
if test "$n" = true; then echo -ne "$strc" ; else echo -e "$strc"; fi
# set +x
# important ces unset, car ex: ansi_code présent dans appel 1 + absent dans appel 2 -> present dans appel 2 sans !
unset c f b F B h n colsize coltamp k args dif tampsize strc ansi_code
return 0
} |
Je vous prie de m'excuser je ne mets pas en forme et je ne relis pas, pas le temps (les commentaires sont sans garantie :roll:), pour l'instant ça fonctionne mais je n'utilise pas tout (je sais que peut-être suivant les options ça cafouille) pour l'usage que j'en fais, exemple:
Code:
1 2 3
| $ source lib/common.sh
$ maxline=62 ; printc -c'1;3' -fwhite -bblue "Qui qu'à vu la clef ???"
Qui qu'à vu la clef ??? |
Ah oui, pourquoi coltamp (?) ... parce que je voulais aligné la sortie des prompt+réponse sur 2 belles colonnes.
J'avais rajouté une option longue mais obligé de la mettre en dernière position des options sinon ça bug (trop compliqué faudrait que je vois un vrai code avec option longues et courtes gérées peu importe l'ordre et la syntaxe [ =, pas =, collé, espacé de -o, --longopt etc ]
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # renvoie la position du curseur dans le terminal au moment de l'appel:
# https://stackoverflow.com/questions/61552574/shell-script-capturing-cursor-terminal-position-on-mac- ...
# ... produces-extra-characters
# https://askubuntu.com/questions/366103/saving-more-corsor-positions-with-tput-in-bash-terminal
get_termposition () {
export $1
exec < /dev/tty
oldstty=$(stty -g)
stty raw -echo min 0
printf "\033[6n" > /dev/tty
IFS=';' read -r -d R -a pos
stty $oldstty
eval "$1[0]=$((${pos[0]:2} - 2))"
eval "$1[1]=$((${pos[1]} - 1))"
unset oldstty
} |
Bout de:
Code:
1 2 3 4 5 6 7 8 9 10 11 12
|
lineno=0
printc -nc'1;3' --col $maxline "Qui qu'à vu les clefs ?: "
get_termposition there
... ça déroule, quand ça écrit une ligne, ça ((lineno++) ...
... une erreur ? r=false, définitif mais continue
# à la fin
tput sc # la position acutelle du curseur dans le terminal
# se place là où le statut était attendu
tput cup $(( ${there[0]} - $lineno )) ${there[1]}
test "$r" = true && printc -c1 -fjaune "OK" || printr "Failed"
tput rc # revient à la position de fin de traitement |
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #!/bin/bash
source lib/common.sh
lineno=0 ; r=false ; maxline=62
printc -nc'1;3' --col $maxline "Qui qu'à vu les clefs ?: "
get_termposition there
for ki in tata mamy tonton toto titi etc; do
test "$lineno" = 0 && echo
echo -n "$ki ..."
test "$ki" = toto && { echo "yes mouah" ; r=true ; break ;} || echo "pas mouah"
((lineno++))
done
tput sc # la position acutelle du curseur dans le terminal
tput cup $(( ${there[0]} - $lineno - 1)) ${there[1]}
test "$r" = true && printc -c1 -fjaune "Ouf ... $ki ... tu me sauves la life" || printc -c1 -fred "Heu ... Ki qui connaît un serrurier ?" # [edit: ou printr qui fait ces options d'office, ...]
tput rc # revient à la position de fin de traitement
unset there |
(c'est un peu à ajuster le tput cup, suivant le contexte ça peut être $lineno-1 qui tombe juste ...)
Sauf imprévu, ça fonctionne pas mal. Pour moi c'est de l'exploration, tout ça demande à être optimisé, si tant est que ça sert à quelque chose :ptdr:
ps: c'est quoi la balise $ dans l'interface ci-dessus ? pour du style ? (je cherchais la palette de couleur à appliquer dans le message ...