Table of Contents
Bash
Bash est un interpréteur de commande, un “shell”. Il possède beaucoup de caractéristiques et fonctions communes avec sh
, ksh
, zsh
ou plus largement *sh
.
Cette page se concentrera sur la prise en main de bash, sa configuration, ses raccourcis clavier, les enchaînements de commandes et quelques tips ; pour la partie programmation/scripting et variables, voir la page Programmation Shell.
Raccourcis clavier
Généraux
Ctrl+d
pour se délogguerCtrl+l
effacer l'écran (=clear
)Ctrl+s
masque la saisie clavierCtrl+q
pour revenirCtrl+c
envoie un SIGINT au processus en coursCtrl+z
suspend (passe en background) le processus courant (voir commandesfg
etbg
)Ctrl+alt+-
ouCtrl+alt++
permet de changer la résolution de XCtrl+alt+Fn
change de terminal virtuel (avec n de 1 à 8)Ctrl+alt+backspace
ferme la session graphiqueCtrl+alt+suppr
la plupart du temps, sert à rebooter
Déplacement curseur
Ctrl+a
place le curseur en début de ligneCtrl+e
place le curseur en fin de ligneCtrl+flèche droite ou gauche
pour se déplacer de mot en mot sur la lignemaj+pageup
oumaj+pagedown
faire défiler la console
Édition de la ligne
Ctrl+u
efface toute la ligne à gauche du curseurCtrl+k
efface toute la ligne à droite du curseurCtrl+w
efface le mot à gauche du curseurEsc+d
efface le mot à droite du curseurCtrl+h
efface le caractère à gauche du curseur (=backspace)alt+u
etalt+l
: passe, respectivement, en majuscules (Uppercase) et minuscules (Lowercase) le texte suivant le curseur jusqu'à la fin du motCtrl+x
Ctrl+e
: copie la ligne courante dans l'étiteur de texte par défaut, pour l'éditer, puis l'exécuter quand on quittera l'éditeur
Rappels et substitutions
Ctrl+r
reverse-i-search : recherche d'une commande dans l'historique ; à nouveauCtrl+r
permet de faire défiler les résultats en cas de réponses multiples ;Ctrl+s
permet de revenir au résultat précédent. (NB : certain terminaux utilisent déjà la séquenceCtrl+S
; pour la désactiver, insérerstty -xion
dans votre.bash_profile
ou.bashrc
. Quand le prompt contient déjà une commande, Ctrl+r permet de rechercher et se rendre à l'endroit du motif :bla bli blu
Ctrl+r
bli
permet de positionner le curseur sur “bli”, très pratique quand la ligne de commande est longue !Esc+@
pour compléter les hostnamesEsc+$
pour compléter les variablesEsc+.
affiche le dernier argument de la dernière commandeEsc+#
commente la ligne courante et annule la commande. Ca permet de la conserver dans l'historique sans l'avoir exécutée, pour la rappeler plus tard (c'est utile quand il nous manque une info en plein milieu de lécriture de la ligne)!motif
permet de lancer la dernière commande saisie commençant par motif!!
(re)lancer la dernière commande!$
le dernier argument de la dernière commande^foo^bar
relancer la dernière commande en remplaçant la première occurrence de “foo” par “bar”. Pour supprimer “foo” :^foo
tout court.!!:gs/foo/bar
relance la dernière commande en remplaçant toutes les occurrences de “foo” par “bar”.
Syntaxe
`<cmd>`
les quotes inversés servent à lancer une commande et afficher le résultat. On peut s'en servir pour utiliser le résultat d'une commande en tant que paramètre d'une autre :ls -l `which vim`
. Cet usage est aujourd'hui déprécié et remplacé par$(commande)
, qui fait pareil.&
suffixer une commande par&
permet de la lancer en tâche de fond<cmd1>;<cmd2>
permet de lancer <cmd1> puis <cmd2> sans condition, sur une même ligne (le;
remplace le retour chariot)<cmd1>&&<cmd2>
permet de lancer <cmd1>, puis <cmd2> uniquement si <cmd1> renvoie true (se termine correctement)<cmd1>||<cmd2>
lancer <cmd1>, puis <cmd2> uniquement si <cmd1> renvoie false<cmd1>|<cmd2>
redirige la sortie standard de <cmd1> vers l'entrée standard de <cmd2><cmd1>|xargs <cmd2>
convertit la sortie de <cmd1> en paramètres de <cmd2><cmd> > <fic>
redirige la sortie (STDOUT) de <cmd> vers le fichier <fic> (le fichier est vidé (>))<cmd> >> <fic>
redirige la sortie de <cmd> à la fin du fichier <fic> (>>)<cmd> 2> <fic>
redirige la sortie d'erreur (STDERR) vers <fic>
On trouvera par exemple <cmd> >/dev/null 2>/dev/null
pour que <cmd> n'affiche rien à l'écran (ni la sortie standard ni la sortie d'erreur).
<cmd> 2> &1
redirige la sortie d'erreur vers la sortie standard (&1)<cmd> < <fic>
redirige le contenu de <fic> sur l'entrée standard de <cmd>- Les apostrophes (quotes) permettant de définir une chaîne de caractère contenant des espaces :
- les doubles quotes
“
interprètent les caractères spéciaux $, \ et ' (quote) - les simples quotes
' n'interprètent aucun caractère spécial
- Les caractères spéciaux sont :
& ~ ; \ ” ' ` # ( ) [ ] | $ * ! ? < >
Variables d'environnement
Elle sont persistantes à un terminal ; on peut les lister avec la commande env
. Voici une liste non exhaustive de variables avec leur utilité :
- HOME : contient le chemin de la home de l'utilisateur
- HOSTNAME : le nom de la machine
- PATH : contient la liste des répertoires dans lesquels le terminal ira rechercher un exécutable automatiquement (sans avoir besoin de spécifier le chemin complet)
- PWD : contient le répertoire courant
- PROMPT_COMMAND : le contenu de cette variable est exécuté à chaque affichage du prompt
- USER, USERNAME ou LOGNAME : contient le login de l'utilisateur
Options
Les options de bash peuvent se modifier au lancement sous forme de paramètre (bash -e
par ex.) ou dans un script via le mot-clé set
. Elles permettent de tuner le shell en modifiant son comportement par défaut.
-e
Avec l'option -e
, bash se termine dès qu'une commande se termine avec un code de retour en erreur (différent de 0). Impossible a activer dans un shell, mais pratique pour éviter que des erreurs non prévues dans un script ne provoquent de gros problèmes.
Cependant cela ne marche pas correctement avec certaines commandes comme grep, qui retourne 1 s'il ne matche pas (ce qui n'est certainement pas une erreur qui vaut le coup que l'on arrête le script). Alors, comme indiqué dans ce thread de stackoverflow :
- soit on gère l'erreur avec un
grep TRUC machin.txt || :
: on gère le retour pour que bash ne la “voit” pas (si aucune action n'est nécessaire :grep TRUC machin.txt || true
suffit ; cependant ce n'est pas idéal, car on masque tous les codes d'erreur (pas que 1). - soit, plus compliqué mais plus pertinent, on créé une fonction “grep” dans notre script pour surcharger la commande système grep, qui va filtrer les codes de retour = 1 (motif non trouvé) mais pas les autres, que bash pourra interpréter (erreur=2 : fichier inexistant par exemple).
#!/bin/bash -e function grep () { local exit_code command grep "$@" || exit_code=$? return $(( exit_code == 1 ? 0 : exit_code )) } grep PATTERN FILE # won't kill script if no matches are found
Rappel : command
permet de lancer la commande qui suit (“grep” ici) parmi les commandes internes et le contenu du $PATH uniquement, afin que notre fonction ne devienne pas récursive !
-x
Pour le débugger un script, ajouter dans le script :
set -x
à partir de l'endroit où l'on veut tracer le scriptset +x
à partir de l'endroit où l'on veut cesser de tracer le script
Autre méthode : lancer le script dans nouveau shell avec : bash -x script
Encore une autre méthode : à la première ligne du script, rajouter “-v” au shebang, par exemple :
#!/bin/sh -v
-n
Pour vérifier la syntaxe d'un script sans le lancer (run-dry) : set -n
(ou bash -n mon_script.sh
)
-o pipefail
Par défaut, après une suite de pipe (|
) bash ne retient que le code de retour de la dernière commande (la plus à droite). En activant l'option pipefail, bash va renvoyer le dernier code de retour en erreur dans la suite de pipes, ou “0” si toutes les commandes se terminent correctement.
Combiné avec -e
, permet de terminer le script courant en cas de code d'erreur non traitée, même celles “cachées” par un pipe.
Par exemple:
#!/bin/bash #set -eo pipefail foo | echo test1 echo test2 #test1 #line 3: foo: command not found #test2
#!/bin/bash set -eo pipefail foo | echo test1 echo test2 #test1 #line 3: foo: command not found
-u
Avec cette option, bash va générer une erreur et stopper son exécution si une variable non déclarée est utilisée. Pour éviter cela, on utilisera la notation ${var-default}
pour s'assurer que si $var n'est pas définie, on lui attribuera la valeur “default” et bash ne génèrera pas d'erreur.
.bashrc
Le fichier .bashrc
contient des script de démarrage et des alias ; il est chargé par défaut lorsqu'on lance bash ; voici mon exemple de .bashrc
:
# ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples # If not running interactively, don't do anything [ -z "$PS1" ] && return # don't put duplicate lines in the history. See bash(1) for more options export HISTCONTROL=ignoredups export EDITOR=vim # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. shopt -s checkwinsize # make less more friendly for non-text input files, see lesspipe(1) [ -x /usr/bin/lesspipe ] && eval "$(lesspipe)" # set variable identifying the chroot you work in (used in the prompt below) if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot) fi # set a fancy prompt (non-color, unless we know we "want" color) #case "$TERM" in #xterm-color) # PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' # ;; #*) # PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' # ;; #esac # Comment in the above and uncomment this below for a color prompt PS1='\[\e[0;30;47m\]$(date +"%H:%M")\[\e[0;33m\] \u@\[\e[0;31m\]\h\[\e[0m\]:\[\e[0;32m\]\W \[\e[0m\]' # If this is an xterm set the title to user@host:dir #case "$TERM" in #xterm*|rxvt*) # PROMPT_COMMAND='echo -ne "\033]0;${USER}@\e[0;31${HOSTNAME}: ${PWD/$HOME/~}\007"' # ;; #*) # ;; #esac # Alias definitions. # You may want to put all your additions into a separate file like # ~/.bash_aliases, instead of adding them here directly. # See /usr/share/doc/bash-doc/examples in the bash-doc package. if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi # enable color support of ls and also add handy aliases if [ "$TERM" != "dumb" ]; then eval "`dircolors -b`" alias ls='ls --color=auto' #alias dir='ls --color=auto --format=vertical' #alias vdir='ls --color=auto --format=long' fi # enable programmable completion features (you don't need to enable # this, if it's already enabled in /etc/bash.bashrc and /etc/profile # sources /etc/bash.bashrc). if [ -f /etc/bash_completion ]; then . /etc/bash_completion fi # droits par defaut des fichiers crees par cet utilisateur umask 027 # pour avoir axx a des cmd telles que ifconfig export PATH=$PATH:/sbin # (20090515) afficher la date et l'heure dans l'historique des commandes HISTTIMEFORMAT="%m/%d_%H:%M:%S " # (20090522) changer la taille de l'historique (cmd history) ; 1000 par défaut HISTSIZE=10000 #echo "---" # affiche une ligne de definition #/home/dude/scripts/aff_lig_def.sh /mnt/data/backup/mesdocs/defs.txt /mnt/data/backup/mesdocs/en.txt #echo "---" w # (20100702) utiliser most pour afficher les pages de man export MANPAGER='most' ### fonctions #function test { # echo $1; #} ### 20110302 append .bashrc ymir et ymir2 (ubuntu 10.10) # Add an "alert" alias for long running commands. Use like so: # sleep 10; alert alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
Tips
Changer le mode d'édition
Par défaut le mode d'édition est de type “emacs-like”, c'est-à-dire que le clavier répond comme sous emac. Pour les aficionados de vi, on peut changer ce mode comme sous vi. On aura donc le mode commande, édition, etc…
set -o vi # pour restaurer le mode "emacs" set -o emacs
Changer le titre
Pour changer le titre de la fenêtre de terminal, une commande passe-partout : echo -ne “\033]0;Nouveau titre\007”
. On peut en faire une fonction pour qu'il soit plus utilisable sous la forme : titreterm “Nouveau titre”
vi ~/.bashrc # modifie le titre de la fenêtre du terminal courant function titreterm { # usage : titreterm Titre if [[ $# -eq 1 && -n $1 ]] then echo -ne "\033]0;$1\007" fi }
Historique des commandes
La commande history
permet d'afficher la liste des dernières commandes exécutées dans le terminal. Pour ajouter un timestamp (horodatage) on peut jouer sur les variables suivantes (à ajouter dans votre ~/.bashrc
ou à exporter) :
# ajouter l'horodatage HISTTIMEFORMAT="%Y/%m/%d_%H:%M:%S " # détermine le nombre de commandes max enregistrées HISTSIZE=20000 # pour supprimer les doublons HISTCONTROL=ignoredups
Pour réafficher la dernière commande, on peut juste appuyer sur la touche de rappel de la dernière commande (“flèche haut”) ; en appuyant une seconde fois on a l'avant-dernière, etc… OU sinon utiliser la commande !
:
# relancer la dernière commande !! # relancer de la dernière commande commençant par "cd" !cd # relancer la 10ème commande de l'historique !10 # relancer l'anvat-dernière commande !-2 # relancer la dernière commande contenant la chaîne "home" !?home # relancer la dernière commande en remplaçant "toto" par "tata" ^toto^tata^
Il existe un outil pour faire des recherches en “temps réel” dans l'historique ; pour l'invoquer on utilise Ctrl+R
. Le prompt est renommé en (reverse-i-search)`':
et on peut saisir une chaîne de caractères ; l'outil va automatiquement rappeler la dernière commande saisie matchant cette chaîne.
PS1 avancé
On peut utiliser la variable PROMPT_COMMAND
pour exécuter un script à chaque affichage du prompt, afin de l'adapter au contexte.
Voici un exemple d'utilisation pour faire varier la couleur de l'utilisateur, la machine et afficher le code de retour de la dernière commande :
# # à insérer dans le .bashrc ou .bash_profile # penser à commenter la ligne "PS1=..." # RED="\[\033[1;31m\]" GREEN="\[\033[0;32m\]" YELLOW="\[\033[0;33m\]" BLUE="\[\033[0;34m\]" GRAY_BG="\[\033[0;30;47m\]" OFF="\[\033[m\]" TIME="\D{%d%m_%H%M%S}" function make_PS1 { # définition couleur "$" en fonction du code de retour précédente commande EXITSTATUS="$?" if [ "${EXITSTATUS}" -eq 0 ] then RET_CMD=${GREEN} else RET_CMD=${RED} fi # définition couleur utilisateur case $(id -u -n) in dude) USR_COL=${GREEN} ;; dude-adm) USR_COL=${BLUE} ;; root) USR_COL=${RED} ;; *) USR_COL=${YELLOW} ;; esac # définition de la couleur de la machine case $(hostname) in pc-perso) HOST_COL=${BLUE} ;; serveur-prod) HOST_COL=${RED} ;; *) HOST_COL=${YELLOW} ;; esac PS1="${GRAY_BG}${TIME}${OFF} ${USR_COL}\u${OFF}@${HOST_COL}\h${OFF}:${YELLOW}\W${RET_CMD} \$${OFF} " } PROMPT_COMMAND=make_PS1
Ce qui donne : 1710_164245 dude@pc-perso:home $
avec des couleurs qui évoluent avec le contexte.
Afficher n fois un caractère
Afficher $N fois le caractère $C :
N=10 C=# printf "%0.s${C}" $(seq 1 ${N})
Désactiver l'alias
Pour afficher si une commande est un alias, on peut faire : alias <cmd>
, par exemple :
alias ls alias ls='ls --color=auto'
Et si on souhaite la lancer sans l'alias (ls
tout court), on peut utiliser la syntaxe '<cmd>'
ou \<cmd>
:
'ls' # ou \ls
Liens/Ressources
- The Art of Command Line (jlevy's GitHub)
- Minimal safe Bash script template (betterdev.blog)
Je pose ledit template ici, mais le lien ci-dessous vaut le détour car il explique chaque best-practice en détail !
#!/usr/bin/env bash set -Eeuo pipefail trap cleanup SIGINT SIGTERM ERR EXIT script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) usage() { cat << EOF # remove the space between << and EOF, this is due to web plugin issue Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-v] [-f] -p param_value arg1 [arg2...] Script description here. Available options: -h, --help Print this help and exit -v, --verbose Print script debug info -f, --flag Some flag description -p, --param Some param description EOF exit } cleanup() { trap - SIGINT SIGTERM ERR EXIT # script cleanup here } setup_colors() { if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then NOFORMAT='\033[0m' RED='\033[0;31m' GREEN='\033[0;32m' ORANGE='\033[0;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' YELLOW='\033[1;33m' else NOFORMAT='' RED='' GREEN='' ORANGE='' BLUE='' PURPLE='' CYAN='' YELLOW='' fi } msg() { echo >&2 -e "${1-}" } die() { local msg=$1 local code=${2-1} # default exit status 1 msg "$msg" exit "$code" } parse_params() { # default values of variables set from params flag=0 param='' while :; do case "${1-}" in -h | --help) usage ;; -v | --verbose) set -x ;; --no-color) NO_COLOR=1 ;; -f | --flag) flag=1 ;; # example flag -p | --param) # example named parameter param="${2-}" shift ;; -?*) die "Unknown option: $1" ;; *) break ;; esac shift done args=("$@") # check required params and arguments [[ -z "${param-}" ]] && die "Missing required parameter: param" [[ ${#args[@]} -eq 0 ]] && die "Missing script arguments" return 0 } parse_params "$@" setup_colors # script logic here msg "${RED}Read parameters:${NOFORMAT}" msg "- flag: ${flag}" msg "- param: ${param}" msg "- arguments: ${args[*]-}"