Une ligne horizontale ajustée avant chaque PROMPT

2014-02-21

Ce serait chouette d’arriver à afficher une ligne horizontale dans le terminal, avant chaque commande : ça permettrait de séparer visuellement les résultats d’exécution.

C’est trop puissant le shell ! :-D

Evidemment, on veut un truc plus évolué que d’afficher un nombre de fois fixe le même caractère car notre fenêtre peut avoir une largeur quelconque. Exclues les solutions du type :

echo --------------------

En googlant, on trouve facilement plusieurs solutions, et après quelques tests et simplifications, je finis par cette commande :

export PROMPT_COMMAND="printf '%*s' `tput cols` | tr ' ' '_' "
  • printf ‘%*s’ : affiche un nombre d’espace déterminé par le paramètre suivant (tput)
  • tput cols : donne le nombre de colonne du terminal. On le met entre anti-guillement pour qu’il soit évalué (et ça va générer le problème, cf plus bas)
  • tr ' ' ‘_’ : remplace les espaces par des undescores depuis la chaîne reçue via le pipe

Ça fonctionne presque parfaitement. Lorsqu’on lance le terminal, la ligne horizontale prend bien la largeur. Mais lorsqu’on change la taille de la fenêtre, la largeur n’est pas ajustée, et le résultat est moche :

Vous avez remarqué le trait qui se poursuit sur les lignes suivantes ? C’est très moche, hein ?

Cette effet est du à l’ordre d’évaluation du shell : au moment où PROMPT_COMMAND est créée, toutes les variables sont d’abord évaluées. Si on regarde le contenu de PROMPT_COMMAND, on comprend mieux le problème :

$ echo $PROMPT_COMMAND
 printf '%*s' 237 | tr ' ' '_'

La commande tput est évaluée, et sa valeur vient alimenter statiquement PROMPT_COMMAND. Mais on peut contourner ce comportement, en obligeant l’évaluation systématique de tput. Voilà une solution :

#PRINT LINE BEFORE EACH PROMPT
 print_line() {
 printf '%*s\n' `tput cols` | tr ' ' '_'
 }
 export PROMPT_COMMAND="print_line"

L’astuce consiste à passer par une fonction (ici print_line) qui est évaluée à chaque appel. Il ne reste plus qu’à insérer ce bout de code dans votre .bashrc et voilà !