#+TITLE: Une Configuration Bash
#+TOC: headlines 4
* Shell interactif
Si le shell n'est pas interactif, on ne configure rien. Tester la présence du prompt est l'une des [[http://www.gnu.org/software/bash/manual/html_node/Is-this-Shell-Interactive_003f.html][deux méthodes]] officielles pour savoir ça.
#+BEGIN_SRC bash :tangle yes
if [ -z "${PS1}" ]
then
return
fi
#+END_SRC
* Prompts
On utilise ~tput~ pour obtenir quelques séquences de contrôle du terminal, pour gérer le gras et le souligné.
#+BEGIN_SRC bash :tangle yes
u_on=$(tput smul)
u_off=$(tput rmul)
bold=$(tput bold)
normal=$(tput sgr0)
#+END_SRC
É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 [[https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh][git-prompt.sh]]).
#+BEGIN_SRC bash :tangle yes
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
#+END_SRC
On peut configurer un prompt classique et efficace, sur deux lignes, vu il y a longtemps dans [[http://shop.oreilly.com/product/9780596003302.do][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.
#+BEGIN_SRC bash :tangle yes
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
#+END_SRC
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]]
:NOTE:
La version Halloween !
export PS1='\n${bold}\u${normal}🎃 ${u_on}\h${u_off}: \w\n🔪 '
:END:
* Environnement général
Une valeur raisonnable pour avoir de la couleur dans le terminal
#+BEGIN_SRC bash :tangle yes
export TERM="xterm-256color"
#+END_SRC
Quand on développe, on veut des core !
#+BEGIN_SRC bash :tangle yes
ulimit -c unlimited
#+END_SRC
Retire les permissions pour group et other. Les répertoires sont créés en 755 et les fichiers en 644.
#+BEGIN_SRC bash :tangle yes
umask 022
#+END_SRC
La touche {{{KBD-(TAB)}}} complète en ignorant la casse
#+BEGIN_SRC bash :tangle yes
bind "set completion-ignore-case on"
#+END_SRC
Affiche les différentes propositions pour compléter, plutôt qu'une alerte
#+BEGIN_SRC bash :tangle yes
bind "set show-all-if-ambiguous on"
#+END_SRC
Met à jour les variables ~LINES~ et ~COLUMNS~ après chaque commande
#+BEGIN_SRC bash :tangle yes
shopt -s checkwinsize
#+END_SRC
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
#+BEGIN_SRC bash :tangle yes
if [ "${EMACS}" != "t" ]
then
set -o emacs
export EDITOR="emacs -nw"
fi
#+END_SRC
Si besoin d'un proxy HTTP
#+BEGIN_SRC bash :tangle no
export http_proxy="proxy.blablabla.fr:80"
#+END_SRC
Lorsqu'il démarre, le shell tronque son fichier d'historique pour ne garder que les 2000 dernières commandes
#+BEGIN_SRC bash :tangle yes
HISTFILESIZE=2000
#+END_SRC
Lorsqu'il termine, le shell ajoute ses 1000 dernières commandes au fichier d'historique (ce dernier n'est pas écrasé).
#+BEGIN_SRC bash :tangle yes
HISTSIZE=1000
shopt -s histappend
#+END_SRC
* 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é.)
#+BEGIN_SRC bash :tangle yes
if [ -z "${SYS_PATH}" ]
then
SYS_PATH="${PATH}"
else
PATH="${SYS_PATH}"
fi
#+END_SRC
Prend tous les répertoires ~~/local/*/bin~. Utilise une [[http://mywiki.wooledge.org/BashFAQ/024][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).
#+BEGIN_SRC bash :tangle yes
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
#+END_SRC
Le reste est sans subtilité. On ajoute quelques répertoires usuels, s'ils sont présents.
#+BEGIN_SRC bash :tangle yes
if [ -d ${HOME}/local/bin ]
then
export PATH="${HOME}/local/bin:${PATH}"
fi
if [ -d ${HOME}/bin ]
then
export PATH="${HOME}/bin:${PATH}"
fi
#+END_SRC
On construit également un ~CDPATH~ succinct (car pratique mais vite piégeux !)
#+BEGIN_SRC bash :tangle yes
export CDPATH="${HOME}"
if [ -d ${HOME}/Bitbucket ]
then
export CDPATH=${HOME}/Bitbucket:${CDPATH}
fi
#+END_SRC
* 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.
#+BEGIN_SRC bash :tangle yes
alias grep="grep --color=auto "
alias h="history 100 "
alias lf="ls -FA "
alias ll="ls -lA "
#+END_SRC
On utilise ~emacsclient~ depuis le terminal pour éditer les fichiers directement dans Emacs en mode graphique
#+BEGIN_SRC bash :tangle yes
if which emacsclient > /dev/null
then
alias ec="emacsclient --alternate-editor=emacs -n "
fi
#+END_SRC
~view~ lance Emacs en mode texte, et ouvre en lecture seule les fichiers passés en argument
#+BEGIN_SRC bash :tangle yes
view() { emacs -nw --eval "(find-file-read-only \"${@}\")"; }
#+END_SRC
~ediff~ réalise dans Emacs (en mode graphique) une comparaison des deux fichiers passés en argument
#+BEGIN_SRC bash :tangle yes
ediff() { ec --eval "(ediff-files \"${1}\" \"${2}\")"; }
#+END_SRC
~work~ lance un terminal Xfce et Emacs cote à cote, en plein écran
#+BEGIN_SRC bash :tangle yes
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
}
#+END_SRC
~old~, ~org~, ~bu~ sont trois alias qui copient ou renomment rapidement une liste de fichiers. Par exemple
#+BEGIN_SRC bash :tangle no
org /etc/fstab
#+END_SRC
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
#+BEGIN_SRC bash :tangle no
old ~/.emacs ~/.bashrc
#+END_SRC
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.
#+BEGIN_SRC bash :tangle yes
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 "
#+END_SRC
* Générer les fichiers :noexport:
- Générer [[elisp:(org-babel-tangle)][bashrc.bash]]
- Générer [[elisp:(org-html-export-to-html)][bashrc.html]]
#+OPTIONS: ^:nil toc:nil d:(not "NOTE") html-postamble:nil
#+HTML_HEAD:
#+HTML_HEAD_EXTRA:
#+MACRO: KBD- @@html:$1@@@@ascii:$1@@
#+MACRO: CTRL- @@html:C-$1@@@@ascii:C-$1@@
#+MACRO: SHIFT- @@html:S-$1@@@@ascii:S-$1@@
#+MACRO: META- @@html:M-$1@@@@ascii:M-$1@@