Une Configuration Bash

Table des matières

Shell interactif

Si le shell n'est pas interactif, on ne configure rien. Tester la présence du prompt est l'une des deux méthodes officielles pour savoir ça.

if [ -z "${PS1}" ]
then
    return
fi

Prompts

On utilise tput pour obtenir quelques séquences de contrôle du terminal, pour gérer le gras et le souligné.

u_on=$(tput smul)
u_off=$(tput rmul)

bold=$(tput bold)
normal=$(tput sgr0)

Étrangement, il n'existe pas de tput rmbold, et pour sortir de l'affichage en gras, il faut faire une remise à zéro de tous les styles avec tput sgr0. La page de manuel de tput indique tput smso et tput rmso pour contrôler l'affichage en gras, mais il semblerait que cela agisse plutôt sur l'affichage en vidéo inversée.

Il existe des raccourcis pour les éléments usuels à mettre dans son prompt, comme \u pour l'utilisateur, \h pour le nom de la machine (jusqu'au premier point), ou \w pour le répertoire courrant (avec ${HOME} abrégé en ~). Mais on peut être plus créatif et ajouter d'autres informations, comme le namespace réseau dans lequel s'exécute le shell, ou des informations sur le status Git quand on est dans un dépôt (avec git-prompt.sh).

ns=$(ip netns identify)
ns=${ns:+⬗${u_on}${ns}${u_off}}

gp() {

    #Empty Git prompt
    return
}

if [ -e ${HOME}/.git-prompt.sh ]
then
    export GIT_PS1_SHOWDIRTYSTATE=1
    . ${HOME}/.git-prompt.sh

    gp()
    {

        ps=$(__git_ps1 '%s')

        if [ -n "${ps}" ]
        then

            echo "⬗${u_on}${ps}${u_off}"
        fi
    }
fi

On peut configurer un prompt classique et efficace, sur deux lignes, vu il y a longtemps dans Unix Power Tools (augmenté du namespace et de Git). Sauf si Bash est lancé dans Emacs ! Car dans ce cas, un prompt plus simple fonctionne mieux.

if [ "${EMACS}" != "t" ]
then
    export PS1='\n${bold}\u${normal}@${u_on}\h${u_off}${ns}$(gp): \w\n> '
else
    export PS1='\n\u@\h:\w > '
fi

Ce qui, dans un terminal Xfce, donne selon le contexte, un prompt court

short_prompt.png

Ou un prompt un peu plus long, avec namespace réseau et informations Git

long_prompt.png

Environnement général

Une valeur raisonnable pour avoir de la couleur dans le terminal

export TERM="xterm-256color"

Quand on développe, on veut des core !

ulimit -c unlimited

Retire les permissions pour group et other. Les répertoires sont créés en 755 et les fichiers en 644.

umask 022

La touche TAB complète en ignorant la casse

bind "set completion-ignore-case on"

Affiche les différentes propositions pour compléter, plutôt qu'une alerte

bind "set show-all-if-ambiguous on"

Met à jour les variables LINES et COLUMNS après chaque commande

shopt -s checkwinsize

Si Bash n'est pas lancé depuis Emacs, on invite ce dernier dans le shell

  • Comportement d'Emacs pour readline (en principe par défaut)
  • L'éditeur par défaut est Emacs en mode texte
if [ "${EMACS}" != "t" ]
then
    set -o emacs
    export EDITOR="emacs -nw"
fi

Si besoin d'un proxy HTTP

export http_proxy="proxy.blablabla.fr:80"

Lorsqu'il démarre, le shell tronque son fichier d'historique pour ne garder que les 2000 dernières commandes

HISTFILESIZE=2000

Lorsqu'il termine, le shell ajoute ses 1000 dernières commandes au fichier d'historique (ce dernier n'est pas écrasé).

HISTSIZE=1000
shopt -s histappend

Ajouts au PATH

Sauvegarde et restaure le PATH système afin de pouvoir charger ce fichier plusieurs fois sans que les modifications apportées ne soient cumulatives. (Elles sont cumulatives quand même en cas de nouveau shell car SYS_PATH n'est pas exporté.)

if [ -z "${SYS_PATH}" ]
then
    SYS_PATH="${PATH}"
else
    PATH="${SYS_PATH}"
fi

Prend tous les répertoires ~/local/*/bin. Utilise une substitution de processus pour ne pas lancer un sous shell et perdre les modifications faites à PATH (ce qui serait le cas avec un simple pipe).

if [ -d ${HOME}/local ]
then
    while read -d '' bin
    do
        PATH="${bin}:${PATH}"
    done < <(find -L ${HOME}/local \
                  -mindepth 2 -maxdepth 2 -type d -iname bin -print0)
fi

Le reste est sans subtilité. On ajoute quelques répertoires usuels, s'ils sont présents.

if [ -d ${HOME}/local/bin ]
then
    export PATH="${HOME}/local/bin:${PATH}"
fi

if [ -d ${HOME}/bin ]
then
    export PATH="${HOME}/bin:${PATH}"
fi

On construit également un CDPATH succinct (car pratique mais vite piégeux !)

export CDPATH="${HOME}"

if [ -d ${HOME}/Bitbucket ]
then
    export CDPATH=${HOME}/Bitbucket:${CDPATH}
fi

Alias et fonctions

Pour mémoire, un espace à la fin d'un alias permet au terme suivant sur la ligne de commande de bénéficier du remplacement des alias. Cependant, les alias sont remplacés immédiatement, avant la lecture de leurs arguments. Il faut donc utiliser une fonction pour que les variables comme ${@} soient évaluées correctement.

alias grep="grep --color=auto "
alias h="history 100 "
alias lf="ls -FA "
alias ll="ls -lA "

On utilise emacsclient depuis le terminal pour éditer les fichiers directement dans Emacs en mode graphique

if which emacsclient > /dev/null
then
    alias ec="emacsclient --alternate-editor=emacs -n "
fi

view lance Emacs en mode texte, et ouvre en lecture seule les fichiers passés en argument

view() { emacs -nw --eval "(find-file-read-only \"${@}\")"; }

ediff réalise dans Emacs (en mode graphique) une comparaison des deux fichiers passés en argument

ediff() { ec --eval "(ediff-files \"${1}\" \"${2}\")"; }

work lance un terminal Xfce et Emacs cote à cote, en plein écran

work() {
    xfce4-terminal --geometry=134x64+0-10 \
                   --default-working-directory="${HOME}/Bureau" \
                   --title=Bureau \
                   --tab --working-directory="${HOME}/Bitbucket" \
                   --title=Bitbucket \
                   > /dev/null 2>&1 & disown

    # Pourquoi ce changement 116x66-6+0 -> 103x56 ?
    emacs --geometry=103x56 > /dev/null 2>&1 & disown
}

old, org, bu sont trois alias qui copient ou renomment rapidement une liste de fichiers. Par exemple

org /etc/fstab

Copie l'original du fichier /etc/fstab vers /etc/fstab.org. L'alias bu fonctionne de même (avec l'extension bu) et correspond au comportement par défaut de la fonction cpmv appelée en sous-main. En revanche

old ~/.emacs ~/.bashrc

Renomme les deux fichiers de configuration vers old.emacs et old.bashrc. Avec ces trois alias, les fichiers cachés commençant par . deviennent apparents.

cpmv() {
    for f in "${@}" ; do

        g=$(echo ${f} | sed -r "{

                 s:/$::g

                 s:(^[^.]*)(\.?)(.*):\1.${CPMV_EXT:-bu}\2\3:g

                 s:^\.?::g
        }")

        cmd="${CPMV_CMD:-cp -R} '${f}' '${g}'"
        echo ${cmd}
        eval ${cmd}

    done
}

alias org="CPMV_EXT=org CPMV_CMD='cp -R' cpmv "
alias old="CPMV_EXT=old CPMV_CMD=mv cpmv "
alias bu="cpmv "