25 Jan 2022 - nicolas
Après avoir un peu ramer à écrire de petits scripts bash pour me faciliter la vie, voici un template que j’utilise souvent :
#! /bin/bash
readonly SCRIPT_NAME=$(basename $0)
styleNormal="\033[0m"
styleStrong="\033[1m"
styleWarning="\033[33m"
styleSuccess="\033[32m"
# Public function template:
functionName() {
if [ $# -lt 1 ]; then
echo -e "${SCRIPT_NAME} ${FUNCNAME[0]} ${styleWarning}parameterName${styleNormal}"
exit 1
fi
}
# Display the source code of this file
howItWorks() {
cat $0
}
# List all functions that do not begin with an underscore _
_listAvailableFunctions() {
cat $0 | grep -E '^[a-z]+[a-zA-Z0-9_]*\(\) \{$' | sed 's#() {$##' | sort
}
if [ $# -eq 0 ]; then
_listAvailableFunctions
exit
fi
"$@"
L’idée est de mettre les actions que vous voulez réaliser dans des fonctions écrites en camelCase ou en snake_case, puis appeler le script suivi du nom de la fonction à exécuter.
Ce comportement est possible grâce à l’utilisation de $@ à la fin du code du script qui contient tous les paramètres passés au script. Si vous ne voulez pas que bash interprète les *, mettez $@ entre double-guillemets "$@".
Les fonctions commençant par _ ne seront pas listées du fait de [a-zA-Z0-9_]*.
La première ligne #! /bin/bash s’appelle le shebang, elle permet de choisir l’interpréteur à utiliser, ici bash.
#! /usr/bin/env bash fonctionne aussi.
Voici en pratique ce que ça donne :

et le code correspondant écrit à partir du template :
#! /usr/bin/env bash
readonly SCRIPT_NAME=$(basename $0)
styleNormal="\033[0m"
styleStrong="\033[1m"
styleWarning="\033[33m"
filterBranches() {
if [ $# -eq 0 ]; then
echo -e "${SCRIPT_NAME} ${FUNCNAME[0]} ${styleWarning}criteriaHere${styleNormal}"
exit
fi
listBranchNames | grep "$1"
}
filterAllBranches() {
git --no-pager branch --all | grep "$1" | sed 's#^* ##' | sed 's# ##' | sed 's#remotes/origin/##' | sed 's/HEAD ->//g' | sort | uniq
}
switchBranch() {
echo -e "\n${styleStrong}Switching to $1...${styleNormal}"
git switch "$1"
}
selectBranch() {
local hint="$*"
echo -e "
${styleStrong}Active branch: ${styleNormal}$(showCurrentBranch)
${styleStrong}Available branches :${styleNormal}"
local availableBranches=$(filterAllBranches "$hint")
PS3="Which number? "
select branchToSwitch in $availableBranches
do
switchBranch "$branchToSwitch"
return
done
}
showCurrentBranch() {
git branch --show-current
}
showOtherBranches() {
git branch | grep --invert-match \* | sed 's# ##'
}
listBranchNames() {
git branch --format='%(refname:short)'
}
# Display the source code of this file
howItWorks() {
less $0
}
# List all functions that do not begin with an underscore _
_listAvailableFunctions() {
cat $0 | grep -E '^[a-z]+[a-zA-Z0-9_]*\(\) \{$' | sed 's#() {$##' | sort
}
if [ $# -eq 0 ]; then
_listAvailableFunctions
exit
fi
"$@"
Pour permettre l’autocompletion que l’on voit dans le gif (en appuyant sur tab), j’ajoute ce genre de code dans mon fichier ~/.bashrc :
listeOptionsAutoCompletion=$(nomCommandePourObtenirLesOptions)
complete -W "${listeOptionsAutoCompletion}" -o bashdefault -o default 'nomCommande'
unset listeOptionsAutoCompletion
unset permet de supprimer la variable
listeOptionsAutoCompletionafin de libérer un peu de mémoire, utile si comme moi vous avez beaucoup de scripts à auto-compléter.
Ce qui nous donne dans le cas de mon script please_git :
please_git_options=$(please_git)
complete -W "${please_git_options}" -o bashdefault -o default 'please_git'
unset please_git_options
Enjoy!