Un prompt bash utile, sans poudre aux yeux

Posté par (page perso) . Modéré par NeoX. Licence CC by-sa
40
7
juil.
2012
Ligne de commande

La configuration de l'invite de commande du shell est un sujet largement traité sur le web. Cependant, on y voit le plus souvent des configurations du type « j'affiche l'horloge sur une ligne complète en arc-en-ciel clignotant ». Pas cool.

Le prompt idéal doit permettre de se rendre compte intuitivement de l'environnement où vous êtes (connexion ssh, root, dépôt git, etc.) et ne doit afficher les informations contextuelles que si elles sont nécessaires. Cool.

Le prompt bash que je vous propose a les fonctionnalités suivantes :

  • couleurs vives pour une connexion root,
  • affichage du nom d'hôte uniquement en cas de connexion distante, avec une couleur différente selon le type de connexion (ssh, telnet),
  • dans les répertoires GIT, affichage du nom de la branche, avec une couleur indiquant le statut des commits
  • rappel du nombre de jobs attachés au terminal, si besoin est
  • alertes batterie et/ou charge système, si besoin est, avec un dégradé de couleurs

Pour utiliser ce prompt, placez simplement une ligne de ce genre dans votre fichier ~/.bashrc :

source ~/prompt.bash

Le code est distribué sous la licence AGPv3 et aurait besoin d'être un peu amélioré. Certaines fonctions ne sont pas factorisées et un bug persiste sur les branches GIT aux noms exotiques.

  • # petites idées

    Posté par . Évalué à  9 .

    J'ai un shell chez moi avec comme tu dis une horloge et tout plein d'infos pas forcément utile.
    Mais l'horloge est quand même pas mal pour avoir une idée de la durée d'une commande (ou savoir quand on l'a lancé). Parce qu'on trouve qu'une commande est lente souvent après l'avoir lancé (et donc sans time).

    Par contre j'ai un truc super génial qui est d'indiquer le code de retour de la commande quand elle est différente de 0.
    et ça c'est aussi bien pratique

    • [^] # Re: petites idées

      Posté par (page perso) . Évalué à  7 .

      Mais l'horloge est quand même pas mal pour avoir une idée de la durée d'une commande (ou savoir quand on l'a lancé). Parce qu'on trouve qu'une commande est lente souvent après l'avoir lancé (et donc sans time).

      Dans CSH il y a une variable de shell spéciale time qui permet d'afficher des statistiques après la terminaison d'une commande, si celle-ci a duré plus d'un certain temps. Chez moi time vaut

      time = (8 
      Time spent in user mode   (CPU seconds) : %Us
      Time spent in kernel mode (CPU seconds) : %Ss
      Total time                              : %Es
      CPU utilisation (percentage)            : %P
      Times the process was swapped           : %W
      Times of major page faults              : %F
      Times of minor page faults              : %R)
      
      
    • [^] # Re: petites idées

      Posté par . Évalué à  3 .

      Mais l'horloge est quand même pas mal pour avoir une idée de la durée d'une commande (ou savoir quand on l'a lancé). Parce qu'on trouve qu'une commande est lente souvent après l'avoir lancé (et donc sans time).

      Super. Je n'y avais jamais pensé. Merci !

      Du coup j'ai ça maintenant, c'est pas très joli mais c'est vraiment pratique.

      PS1='[\D{%d/%m %T}]\u@${debian_chroot:+($debian_chroot)}\h:\w\$ '
      
      
  • # Je suis peut-être une bille, mais…

    Posté par (page perso) . Évalué à  2 .

    ego@Urist:~$ source bin/prompt.bash 
    bash: bc : commande introuvable
    bash: [: -gt : opérateur unaire attendu
    bash: bc : commande introuvable
    bash: [: -gt : opérateur unaire attendu
    bash: [: -lt : opérateur unaire attendu
    bash: [: -lt : opérateur unaire attendu
     [ego ~] $ 
    
    

    Je ne sais pas vraiment d’où ça vient…

    • [^] # Re: Je suis peut-être une bille, mais…

      Posté par . Évalué à  2 .

      bc semble ne pas être installé http://www.gnu.org/software/bc/

      Pour ma part, c'était acpi qui ne l'était pas. (mais bon, m'en fiche de la batterie). Aussi j'ai un peu adapté le code (du coup je me retrouve avec un prompt qui ressemble vachement à l'ancien).

      # add battery status
      #PS1="\[\$(battery_color)\]\$(battery) ${NO_COL}$PS1"
      
      # add colored load average
      #PS1="\[\$(load_color)\]\$(load_out)${NO_COL}$PS1"
      
      

      Please do not feed the trolls

    • [^] # Re: Je suis peut-être une bille, mais…

      Posté par (page perso) . Évalué à  3 .

      moi j'ai encore plus long

      (standard_in) 1: illegal character: :
      (standard_in) 1: parse error
      (standard_in) 1: illegal character: :
      (standard_in) 1: illegal character: :
      (standard_in) 1: illegal character: :
      bash: [: -gt : opérateur unaire attendu
      (standard_in) 1: illegal character: :
      (standard_in) 1: parse error
      (standard_in) 1: illegal character: :
      (standard_in) 1: illegal character: :
      (standard_in) 1: illegal character: :
      bash: [: -gt : opérateur unaire attendu
      bash: acpi : commande introuvable
      bash: [: -lt : opérateur unaire attendu
      bash: acpi : commande introuvable
      bash: [: -lt : opérateur unaire attendu
      
      

      je vois plusieurs problèmes:
      THIS_TTY=ttyps aux | grep $$ | grep bash | awk '{ print $7 }'
      -1: quand on est en terminal, chez moi ca donné pts/1 par exemple pas un ttyX
      -2: le résultat entre donne déjà un préfixe de tty donc faut supprimer le tty pour avoir
      THIS_TTY=ps aux | grep $$ | grep bash | awk '{ print $7 }'

      faire un test sur acpi
      if which acpi 2>/dev/null ; then

      • [^] # Re: Je suis peut-être une bille, mais…

        Posté par . Évalué à  10 .

        Cette histoire de tty, c’est du n’importe quoi !

        1. le grep $$ : $$ peut se trouver inclus dans un autre pid (celui d’un autre bash) ou comme argument d’un programme (le "bash" aussi) ou dans l’occupation mémoire d’un autre processus (→ pourquoi le u dans le ps ?) → "\A$$\Z"¹ ;

        2. deux greps → un seul "\A$$\Z.* /bin/bash\Z"¹ ;

        3. deux greps et un awk → un seul awk (awk "/\A$$\Z* \/bin\/bash\Z/ {print \$7}"¹) ;

        4. en plus, on pourrait plus simplement regarder vers quoi pointe /proc/$$/fd/0

        5. … ou utiliser la commande prévue pour : tty.

        ¹ remplacer \A par \< et \Z par \>. La prévisualisation est bizarre : certaines barre obliques inverses (\) ne sont pas affichées si elles ne sont pas doublées et elle choisit les inférieur/supérieur à qui sont interprétés…

    • [^] # Re: Je suis peut-être une bille, mais…

      Posté par (page perso) . Évalué à  9 .

      Le bc pourrait être remplacer par du shell :

      - 210 tmp=$(echo $load*100 | bc)
      + 210 tmp=$((load*100))
      
      

      Si on a besoin d'un calcul flottant, on peut aussi utiliser les fonctions arithmétiques de awk.

    • [^] # Re: Je suis peut-être une bille, mais…

      Posté par (page perso) . Évalué à  1 .

      Pour ma part j'ai ceci :

      (standard_in) 1: illegal character: :
      (standard_in) 1: syntax error
      (standard_in) 1: illegal character: :
      (standard_in) 1: illegal character: :
      bash: [: -gt : opérateur unaire attendu
      (standard_in) 1: illegal character: :
      (standard_in) 1: syntax error
      (standard_in) 1: illegal character: :
      (standard_in) 1: illegal character: :
      bash: [: -gt : opérateur unaire attendu
      bash: [: 35% : nombre entier attendu comme expression
      bash: [: 35% : nombre entier attendu comme expression
      bash: [: 35% : nombre entier attendu comme expression
      bash: [: 35% : nombre entier attendu comme expression
      bash: [: 35% : nombre entier attendu comme expression
       35% [doo ~] $
      
      

      Afficher le pourcentage, ça n'est pas l'idéal pour la comparaison. Faire un sed 's/%//g' serait pas mal.

      Pour ce qui est de -gt & cie, là franchement, merci bash pour ces indications fort peu explicites…

      Love, bépo.

  • # Mon résultat.

    Posté par (page perso) . Évalué à  3 .

    No support for device type: power_supply
    bash: [: -lt : opérateur unaire attendu
    No support for device type: power_supply
    bash: [: -lt : opérateur unaire attendu
    fatal: ambiguous argument 'origin/..': unknown revision or path not in the working tree.
    Use '--' to separate paths from revisions

    A chaque CR c'est plutot pénible. Pour info un '$ acpi --battery' me renvoie le msg suivant puisque je suis sur un ordi de bureau.

    No support for device type: power_supply

    Pour les 2 dernières lignes je n'ai pas encore regardé.

  • # Et zsh ?

    Posté par (page perso) . Évalué à  9 .

    À tout hasard, est-ce qu'il y aurait un volontaire pour faire la même chose pour zsh ?

    • [^] # Re: Et zsh ?

      Posté par (page perso) . Évalué à  2 .

      Regardes déjà celui du site grml, il est pas trop mal.

      http://grml.org/zsh/

    • [^] # Re: Et zsh ?

      Posté par (page perso) . Évalué à  6 . Dernière modification : le 07/07/12 à 16:46

      Je ne sais pas si ça répond exactement à ça mais voici quelques liens qui devraient au moins aider un peu :

      http://stevelosh.com/blog/2010/02/my-extravagant-zsh-prompt/ : un prompt plutôt sympa, axé git et hg

      https://github.com/robbyrussell/oh-my-zsh/ pour avoir une config sympa et devrait pour répondre intégralement ou presque, non ? (en général commencer par oh-my-zsh est une pas mal)

      • [^] # Re: Et zsh ?

        Posté par (page perso) . Évalué à  3 .

        Une petite précision : le premier lien utilise en fait le second…
        J'ai utilisé pendant quelques temps (au moins un an je pense) le premier (donc le second) avec grand plaisir, vraiment sympa. L'affichage de la batterie à droit est plutôt cool. Après je l'ai abandonné simplement parce que je suis (temporairement désormais) passé sous windows/cygwin et ça c'est moche.

        • [^] # Re: Et zsh ?

          Posté par . Évalué à  -1 .

          Pour zsh, j'ai un joli prompt:
          zsh
          Il m'indique l'heure, le jour de la semaine, la date du mois, et sur la deuxième ligne mon login, le nom de la machine où se trouve le shell, et le répertoire courant !!
          Pour avoir ça, il faut simplement paramétrer la variable PS1 dans le fichier ~/.zshrc sur deux lignes de cette manière:

          PS1="echo '\033[00;34m'%T le %wecho '\033[01;31m\n'
          %B%n%b@%m: %~> "

    • [^] # Re: Et zsh ?

      Posté par . Évalué à  3 .

      il y a le fameux Oh-my-zsh avec plusieurs thèmes prompts proposés.

    • [^] # Re: Et zsh ?

      Posté par . Évalué à  2 .

      http://pastebin.com/nKMdKsLy
      En voici un qui reprend une partie des fonctionnalités et qui en ajoute d'autres :

      • pas de gestion de l'état des commits
      • pas de gestion fines des processus en background
      • pas de gestion des connexions ssh
      • pas de gestion de la batterie (mais je suis sur un fixe donc je peux pas tester de toute manière)
      • ajout de l'heure à gauche de l'écran

      Je suis dans ma tour d'ivoire (rien à foutre des autres, dites moi un truc pour moi), si je ne pose pas explicitement une question pour les 99%, les kévin, les Mm Michu alors c'est que je ne parle pas d'eux.

    • [^] # Re: Et zsh ?

      Posté par (page perso) . Évalué à  1 .

      Mon petit mien au passage : https://gist.github.com/3094451
      Ce qui peut donner : « (±|master|●1|+1|…1|⚡) » , scm | branche courante | modifs indexées | modifs non indexées | fichiers non trackés | état du workspace

  • # uptime me renvoit mon load avec des virgule

    Posté par (page perso) . Évalué à  3 .

    Ma commande uptime me renvoie mes load avec des virgule plutôt que des points (sur une de mes machines mais pas sur l'autre). Du coup le sed ne fonctionne plus du tout.

    Du coup à la place de :

    load=`uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\).*/\1/" -e "s/ //g"`
    
    

    peut être :

    load=`cat /proc/loadavg | sed "s/ .*//g"`
    
    
    • [^] # Re: uptime me renvoit mon load avec des virgule

      Posté par . Évalué à  3 .

      Pour ton problème de virgule c'est certainement une histoire de locale. Tu peux essayer avec LANG=C :

      load=`LANG=C uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\).*/\1/" -e "s/ //g"`
      
      

      Sinon, j'aime bien :

      load=`awk '{print $1}' /proc/loadavg`
      
      
      • [^] # Re: uptime me renvoit mon load avec des virgule

        Posté par (page perso) . Évalué à  2 .

        Souvent je me dis "où est-ce que je pourrais aller regarder pour avoir un bon exemple plutôt que de trop réfléchir ?" et donc là je me suis dit qu'aller regarder le plugin load de munin serait une bonne idée. En adaptant un peu pour prendre la première valeur moyenne cela donne :

        load=`cut -f1 -d' ' < /proc/loadavg`
        
        
  • # Retour d'expérience

    Posté par (page perso) . Évalué à  6 .

    Tout d'abord, je ne te remercies vraiment pas pour ce script, je viens de perdre mon après-midi à le personnaliser, fignoler, … ;)

    Plus sérieusement, pour savoir si on est root ou pas, c'est plus simple d'utiliser :

    if [[ ${EUID} == 0 ]]

    Pour git, si la branche origin/branch n'existe pas, il y a une erreur :

    fatal: ambiguous argument 'origin/my-prompt..my-prompt': unknown revision or path not in the working tree.
    Use '--' to separate paths from revisions

    Je me souviens aussi qu'il y a un meilleur moyen pour obtenir les infos de git, au lieu d'utiliser des commandes comme git branch, git diff, etc. Mais je sais plus quel est ce meilleur moyen, je te laisse chercher ;)

    Sinon sur le web y a déjà plein d'autres prompt bash pour git, avec certaines choses utiles, mais malheureusement plein d'autres trucs inutiles (mettre dans une couleur différente selon l'heure du dernier commit, …). Juste le nom de la branche avec quelques couleurs, c'est très bien !

    « Un animal d'une atterrante stupidité : il est persuadé que si vous ne le voyez pas, il ne vous voit pas non plus » (H2G2)

    • [^] # Re: Retour d'expérience

      Posté par (page perso) . Évalué à  4 .

      Pour avoir la branche avec git :

      __git_ps1 ' (%s)'
      
      

      Il existe deux catégories de gens : ceux qui divisent les gens en deux catégories et les autres.

  • # Il me semble que

    Posté par (page perso) . Évalué à  4 . Dernière modification : le 07/07/12 à 20:40

    Sur des simples crochets on protège les variables avec des doubles quotes.
    Sinon on utilise la syntaxe double crochet avec des tests en == & co, ce qui evite des erreurs de syntaxes sur des variables vides ou de type non attendu
    Puis tant qu'a faire plutôt que de mixer les `cmd` et les $(cmd) autant utiliser la 2eme, la 1ere est obsolète

    edit : une source

    Is it a Bird? Is it a Plane?? No, it's Super Poil !!!

    • [^] # Re: Il me semble que

      Posté par (page perso) . Évalué à  1 .

      Je me répond a moi même, afin d'éviter quelques fork, quelques pistes (parce que sur ma VM l’exécution du script ajoute dans les 0.3 de load :x) :
      THIS_TTY=tty$(ps aux | awk -v pid=$$ '/pid/ && /bash/ { print $7 }')
      SSH_IP=${SSH_CLIENT%% *}
      pour le loadavg
      awk '{ print $1 }' /proc/loadavg

      Is it a Bird? Is it a Plane?? No, it's Super Poil !!!

  • # mise à jour ?

    Posté par . Évalué à  7 .

    J'espère qu'après autant de retour il va y avoir des updates :)
    * passer de bc à sh
    * gérer l'absence de batterie
    * tester la présence du binaire acpi lors du source ?

    Super idée en tout cas.

    "La liberté de tout dire, n'a d'ennemis, que ceux qui veulent se réserver, le droit de tout faire"

  • # Comme dirait Père Blaise

    Posté par . Évalué à  3 .

    Vous êtes des malaaaaaaades !

  • # Multiples batteries

    Posté par . Évalué à  1 .

    Merci pour cette très bonne initiative !
    Pour ma part, mon portable ayant 2 batteries, j'ai fait une petite modif dans la procédure "battery()": je calcule la valeur moyenne….

    battery()
    {
        cumul=0
        i=0
        values=$(acpi --battery | sed "s/^Battery .*, \([0-9]*\)%.*$/\1/") 
        for valeur in $values
        do
            ((cumul += valeur))
            ((i++))
        done
        ((bat = cumul / i))
    
        if [ ${bat} -lt 90 ] ; then
            echo -n " ${bat}%"
        else
            echo -n ""
        fi
    }
    
    
  • # Coloration différente de la sortie d'erreur et de la sortie standard ?

    Posté par . Évalué à  3 .

    Personnaliser le prompt, c'est bien mais existe-t-il un moyen de faire ressortir, en rouge par exemple, tout ce qui sort sur la sortie d'erreur ?

  • # Y'a du boulot...

    Posté par (page perso) . Évalué à  6 .

    …A faire.

    Les variables non "quotées", ni declaree en "local" dans les fonctions, les * non-despecialisees… ouais y'a encore beaucoup a faire.

    Je pense que ton script est dangeureux.

    tu contredis beaucoup de points de la FAQ de reference http://mywiki.wooledge.org/BashFAQ/

  • # vu que l'on parle du prompt

    Posté par (page perso) . Évalué à  1 . Dernière modification : le 09/07/12 à 15:49

    J'ai constaté un comportement bizarre si j'utilise:

    PS1="\033[1;32m\u\033[0;0m \$"
    
    

    Et pas quand j'utilise en plus \! comme:

    PS1="[ \! ] \033[1;32m\u\033[0;0m \$"
    
    

    Le soucis et que dans le 1er cas lorsque j'utilise les flèches haut bas pour naviguer dans l'historique il y a des lignes qui se superpose. j'ai essayer de jouer avec les séquences d'échappement ANSI pour positionner le curseur et supprimer ceux qui suivait mais un peu trop complexe à gérer pour un simple prompt. Je sais pas si je suis le seul avec ce soucis.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.