« Bash » : différence entre les versions
(12 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 17 : | Ligne 17 : | ||
== [http://www.davidpashley.com/articles/writing-robust-shell-scripts Options Bash] == | == [http://www.davidpashley.com/articles/writing-robust-shell-scripts Options Bash] == | ||
<kode lang=bash> | <kode lang=bash> | ||
# arrête le script si une commande (ligne complète) | # arrête le script si une commande (ligne complète) échoue (retourne une valeur différente de true) | ||
set -e | set -e | ||
# désactiver l'option | # désactiver l'option | ||
Ligne 100 : | Ligne 100 : | ||
== [https://gist.github.com/cosimo/3760587 GNU getopt] == | == [https://gist.github.com/cosimo/3760587 GNU getopt] == | ||
<kode lang='bash'> | <kode lang='bash'> | ||
OPTS=$(getopt -o vhn -l verbose,help,dry-run -n 'parse-options' -- "$@") | |||
OPTS= | # -o short option name | ||
# -l long option name | |||
# -n name used when it reports errors | |||
# -- indicate the ends of the options | |||
# option format: | |||
# h no-value | |||
# h: mandatory with value | |||
# h:: optinal with value | |||
if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi | if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi | ||
eval set -- "$OPTS" | eval set -- "$OPTS" | ||
VERBOSE=false | |||
HELP=false | HELP=false | ||
DRY_RUN=false | |||
while true | while true | ||
do | |||
case "$1" in | case "$1" in | ||
-v | --verbose ) VERBOSE=true; shift ;; | |||
-h | --help ) HELP=true; shift ;; | -h | --help ) HELP=true; shift ;; | ||
- | -n | --dry-run ) DRY_RUN=true; shift ;; | ||
-- ) shift; break ;; | -- ) shift; break ;; | ||
* ) break ;; | * ) break ;; | ||
Ligne 122 : | Ligne 131 : | ||
echo HELP=$HELP | echo HELP=$HELP | ||
echo STACK_SIZE=$STACK_SIZE | echo STACK_SIZE=$STACK_SIZE | ||
if $HELP | |||
then | |||
usage | |||
exit 0 | |||
fi | |||
</kode> | </kode> | ||
Ligne 177 : | Ligne 192 : | ||
# masque stdout et stderr | # masque stdout et stderr | ||
commande &> /dev/null | |||
commande >/dev/null 2>&1 | commande >/dev/null 2>&1 | ||
Ligne 182 : | Ligne 198 : | ||
commande 2>&1 | tee fichier | commande 2>&1 | tee fichier | ||
# tee -a fichier pour ajouter à la suite du fichier | # tee -a fichier pour ajouter à la suite du fichier | ||
# with multiple commands | |||
{ | |||
echo "1" | |||
echo "2" | |||
} 2>&1 | tee -a log/$(date '+%Y-%m-%d').log | |||
# affiche la sortie de commande dans la console et l'écrit aussi dans fichier. Utile pour conserver les couleurs. | # affiche la sortie de commande dans la console et l'écrit aussi dans fichier. Utile pour conserver les couleurs. | ||
Ligne 312 : | Ligne 333 : | ||
done | done | ||
# for element in $(ls -t) ne permet pas gérer les noms avec espaces | # for element in $(ls -t) ne permet pas gérer les noms avec espaces | ||
# read file names in a file and delete them | |||
while IFS= read -r f; do [ -f "$f" ] && rm -f "$f"; done < list.txt | |||
</kode> | </kode> | ||
Ligne 325 : | Ligne 349 : | ||
# en une ligne | # en une ligne | ||
if [ | if [ expression ]; then echo 1; echo 2; else echo 3; fi | ||
</kode> | </kode> | ||
= [[ ]] = | = [[ ]] = | ||
<kode lang=bash> | <kode lang=bash> | ||
# commande | # if expression is true then execute commande | ||
[[ | [[ expression ]] && command | ||
# commande | # if expression is false then execute commande | ||
[[ | [[ expression ]] || command | ||
</kode> | |||
== Booleans == | |||
<kode lang=bash> | |||
var1=false | |||
if $var1 | |||
if [ $var1 = true ] | |||
if [[ $var1 = true ]] | |||
</kode> | </kode> | ||
Ligne 367 : | Ligne 400 : | ||
fi | fi | ||
</kode> | </kode> | ||
{{info | Escape the following characters {{boxx|( ) .}}}} | |||
== Entiers == | == Entiers == |
Dernière version du 16 juin 2024 à 13:07
Liens
Début de fichier
# spécifie quel shell doit être utilisé #!/usr/bin/bash set -e set -o pipefail set -u wd="$(dirname "$(realpath "$0")")" |
Options Bash
# arrête le script si une commande (ligne complète) échoue (retourne une valeur différente de true) set -e # désactiver l'option set +e # arrête le script si une commande (dans un pipe) retourne une valeur différente de true set -o pipefail # arrête le script si une variable non-initialisée est utilisée set -u |
Debug
Afficher des informations au fil de l'éxecution du script
# lancer le script en mode debug bash -x script.sh # modifier la premier ligne du script pour l'éxecuter en mode debug #!/bin/bash -xv |
Debug a Shell Script Under Linux
Lire les entrées du clavier
Lis le clavier jusqu'à ce que la touche entrée soit pressée.
read input # avec du texte read -r -p 'Entrée : ' input # -r : \ n'agit pas comme un caractère d'espacement echo $input # sans afficher la saisie: pour les mots de passe read -r -s -p 'Password : ' password echo # saut de ligne car l'appuie sur entrée n'a pas été pris en compte |
Menu: select / case
echo Titre PS3='question? ' select choix in \ "Premier choix" \ "Second choix" \ "Quitter" do echo Vous avez choisi $choix case $REPLY in 1) echo choix n°$REPLY;; 2) echo choix n°$REPLY;; 3) exit 0;; *) echo $REPLY: choix invalide;; esac echo # saut de ligne done |
Arguments passés au script
$*
liste des arguments séparés par des espaces. Attention aux arguments contenant des espaces"$@"
liste des arguments entourés par des guillemets et séparés par des espaces$1 ... $9 ${10}
arguments de position, utiliser les accolades à partir de 10$#
nombre d'arguments
# entrée: "fichier 1.jpg" fichier\ 2.jpg for file in "$@" ; do ... ; done # fichier\ 1.jpg # fichier\ 2.jpg # $* pose problème avec les arguments contenant des espaces car le séparateur d'argument est aussi espace # il faut donc remplacer toutes les occurrences d'espaces dans les arguments ${*// /\\ } # fichier\ 1.jpg fichier\ 2.jpg ARGS=("$@") "${ARGS[@]}" # tous les arguments "${ARGS[0]}" # premier argument |
GNU getopt
OPTS=$(getopt -o vhn -l verbose,help,dry-run -n 'parse-options' -- "$@") # -o short option name # -l long option name # -n name used when it reports errors # -- indicate the ends of the options # option format: # h no-value # h: mandatory with value # h:: optinal with value if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi eval set -- "$OPTS" VERBOSE=false HELP=false DRY_RUN=false while true do case "$1" in -v | --verbose ) VERBOSE=true; shift ;; -h | --help ) HELP=true; shift ;; -n | --dry-run ) DRY_RUN=true; shift ;; -- ) shift; break ;; * ) break ;; esac done echo HELP=$HELP echo STACK_SIZE=$STACK_SIZE if $HELP then usage exit 0 fi |
test des arguments et usage
usage() { echo "$(basename $0) arg1" echo "" echo "arg1: ..." } # si aucun argument n'est renseigné ou si le premier argument est vide, on appel usage et on quitte if [[ $# == 0 ]] || [[ -z $1 ]]; then usage exit 1 fi |
shift
Permet de consommer le premier argument et de décaler tous les autres
if [[ $1 == '--mon-option' ]]; then # shift permet de décaler tous les arguments d'une position vers la gauche: $2 → $1, $3 → $3, etc shift fi # si $1 == --mon-option, $2 remplacera $1 pour l'appel à MaFonction MaFonction $1 |
Redirections
- 0 is stdin, l'entrée standard
- 1 is stdout, la sortie standard
- 2 is stderr, les erreurs
# redirige stdout vers un fichier, il est créé s'il n'existe pas, sinon il est écrasé commande > fichier # équivalent à : commande 1> fichier # commande >> fichier pour ajouter à la suite du fichier # redirige stderr vers un fichier commande 2> fichier # redirige stderr vers stdout commande 2>&1 # redirige stdout et stderr vers file.log # redirige stdout vers file.log, puis stderr vers stdout donc vers file.log commande >file.log 2>&1 # redirige stderr vers le terminal et stdout vers un fichier # redirige stderr vers stdout donc vers le terminal, puis stdout vers file.log commande 2>&1 >file.log # masque stdout et stderr commande &> /dev/null commande >/dev/null 2>&1 # redirige stderr vers stdout (terminal) et écrit stdout (et stderr) vers un fichier commande 2>&1 | tee fichier # tee -a fichier pour ajouter à la suite du fichier # with multiple commands { echo "1" echo "2" } 2>&1 | tee -a log/$(date '+%Y-%m-%d').log # affiche la sortie de commande dans la console et l'écrit aussi dans fichier. Utile pour conserver les couleurs. script -q -c 'commande' fichier |
Variables
# affectation d'une variable, attention pas d'espaces autour du = ma_variable="valeur" # affichage du contenu d'une variable echo $ma_variable # valeur echo $ma_variable1 # echo ${ma_variable}1 # valeur1 # par défaut toutes les variables sont globales # locale permet de définir une variable locale locale ma_variable="valeur" # variable readonly readonly my_ro_var='value' # suppression d'une variable unset ma_variable # affichage de l'ensemble des variables définies dans le shell set |
Par défaut, le scope des variables est globale. |
Les noms de variables ne peuvent pas contenir de - |
Variables spéciales
$$ | PID du shell courant |
$! | PID du dernier travail lancé en arrière plan |
$? | code retour de la dernière commande |
Variables d'environnement
$HOME | chemin du répertoire personnel de l'utilisateur |
$PATH | liste des chemins de recherche des commandes exécutables |
$PPID | PID du processus père du shell |
$PWD | chemin du répertoire courant |
$RANDOM | nombre entier aléatoire compris entre 0 et 32767 |
# Afficher toutes les variables d'environnement printenv |
Définies dans les fichiers suivants:
- /etc/profile
- /etc/profile.d/*
- $HOME/.zshrc
Stocker le résultat d'une commande
currentpath=$(pwd) cd "$currentpath" |
String vs entier
Par défaut une variable contient un string. Mais on peut déclarer une variable comme un entier.
v=1 # 1 v+=1 # 11 # declare v comme un entier declare -i v v=1 # 1 v+=1 # 2 |
For
listeDeChiffres="1 2 3 4 5" for chiffre in $listeDeChiffres do echo chiffre : $chiffre done # équivalent sur une seule ligne for chiffre in $listeDeChiffres ; do echo chiffre : $chiffre ; done for lettre in {a..z} # i à 5 puis de 10 à 50 et enfin à 100 et 110 for i in 5 {10..50} 100 110 # i de 10 à 50 avec un incrément de 2 for i in {10..50..2} # i de 1 à 5 avec un incrément de 1 for (( c=1; c<=5; c++ )) # boucle infinie for (( ; ; )) |
While
# tant que name est vide on demande sa saisie while [ -z $name ] do read -p 'Name : ' name done # tant que firefox tourne while pgrep firefox >/dev/null do read -p 'Fermez Firefox avant de continuer.' askclosefirefoxinput done # lister les dossiers par ordre décroissant de création ls -t | while read element do [[ -d $element ]] || continue echo $element done # for element in $(ls -t) ne permet pas gérer les noms avec espaces # read file names in a file and delete them while IFS= read -r f; do [ -f "$f" ] && rm -f "$f"; done < list.txt |
if / else
if (expression); then echo 1 elif ! (expression); then echo 2 else echo 3 fi # en une ligne if [ expression ]; then echo 1; echo 2; else echo 3; fi |
[[ ]]
# if expression is true then execute commande [[ expression ]] && command # if expression is false then execute commande [[ expression ]] || command |
Booleans
var1=false if $var1 if [ $var1 = true ] if [[ $var1 = true ]] |
Strings
if [[ $1 == $2 ]] # vrai si le string contenu dans $1 est le même que celui dans $2 if [[ $1 != $2 ]] # vrai si le string contenu dans $1 n'est pas le même que celui dans $2 |
Do not use the ${var} form to call the variable, use $var instead. |
Expressions rationnelles (regex) et patrons de correspondance
# utilisation de *: startwith, endwith, contains if [[ $1 == XXX* ]] # vrai si $1 commence par XXX if [[ $1 == *XXX ]] # vrai si $1 se termine par XXX if [[ $1 == *XXX* ]] # vrai si $1 contient XXX if [[ $1 == *'XXX YYY'* ]] # vrai si $1 contient XXX YYY # expression rationnelle if [[ $1 =~ [0-9][0-9]\.jpg$ ]] # vrai si $1 respecte l'expression rationnelle if [[ $mon_texte =~ http://[a-zA-Z0-9._/]+\.jpg ]] then echo "OK: ${BASH_REMATCH}" else echo "KO" fi # groupes. Ex: 20160530 → 2016-05-30 if [[ $mon_texte =~ ([0-9]{4})([0-9]{2})([0-9]{2}) ]]; then echo "${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}" fi |
Escape the following characters ( ) . |
Entiers
if [[ $1 -gt $2 ]] # vrai si l'entier contenu dans $1 est plus grand que celui dans $2 if [[ $1 -lt $2 ]] # vrai si l'entier contenu dans $1 est plus petit que celui dans $2 if [[ $1 -ge $2 ]] # vrai si l'entier contenu dans $1 est plus grand ou égual à celui dans $2 if [[ $1 -le $2 ]] # vrai si l'entier contenu dans $1 est plus petit ou égual à celui dans $2 if [[ $1 -eq $2 ]] # vrai si l'entier contenu dans $1 est égual à celui dans $2 if [[ $1 -ne $2 ]] # vrai si l'entier contenu dans $1 n'est pas égual à celui dans $2 |
Il est préférable d'utiliser la forme (( ))
|
Opérateurs ET, OU
if [[ $1 -gt $2 && $1 -lt 100 || $1 -eq 0 ]] if [[ $1 -gt $2 && ($1 -lt 100 || $1 -eq 0) ]] # avec des parenthèses |
Fichiers, dossiers
if [[ -e $1 ]] # vrai si $1 existe : fichier, répertoire ou lien pointant vers un fichier ou répertoire existant if [[ -f $1 ]] # vrai si $1 est un fichier ou lien pointant vers un fichier existant if [[ -d $1 ]] # vrai si $1 est un répertoire if [[ -L $1 ]] # vrai si $1 est un lien, même si le lien ne pointe pas vers un fichier ou répertoire existant if [[ -r $1 ]] # vrai si $1 est accessible en lecture if [[ -w $1 ]] # vrai si $1 est accessible en écriture if [[ -x $1 ]] # vrai si $1 est exécutable |
Différences entre [ ] et [[ ]]
- [[ ]] ne fonctionne qu'avec Bash et Korn shell.
- Avec [[ ]], il n'est pas nécessaire d'entourer les variables de quotes
- Avec [[ ]], les parenthèses n'ont pas besoin d'être échappées
La commande test ou [ ]
if test -e "$1" # vrai si $1 existe : fichier, répertoire ou lien if [ -f "$1" ] # vrai si $1 est un fichier if [ -d "$1" ] # vrai si $1 est un répertoire if [ -r "$1" ] # vrai si $1 est accessible en lecture if [ -x "$1" ] # vrai si $1 est éxécutable if [ ! ] # opérateur de négation if [ -n "$1" ] # vrai si $1 est de longueur supérieur à 0 if [ -z "$1" ] # vrai si $1 est de longeur 0, ex: pas d'argument if [ e1 -a e2 ] # vrai si e1 ET e2 sont vrai if [ e1 ] && [ e2 ] # il est plutôt conseillé d'utiliser cette forme if [ e1 -o e2 ] # vrai si e1 OU e2 sont vrai if [ e1 ] || [ e2 ] # il est plutôt conseillé d'utiliser cette forme if [ \(e1 -o e2\) -a e3 ] # parenthèses if { [ e1 ] || [ e2 ] ; } && [ e3 ] # il est plutôt conseillé d'utiliser cette forme |
(( ))
Permet de faire des comparaisons d'entiers
if (( $1 > 10 )) if (( $1 < 20 )) if (( $1 == 15 )) if (( $1 != 15 )) if (( $1 % 100 == 0 )) echo $(( 1 == 1 )) # vrai : 1, faux : 0 |
Mais aussi des opérations sur les entiers
echo $(( $1 += 1 )) # ajoute 1 à $1 echo $(( i += 1 )) # ajoute 1 à i # nombre aléatoire entre 0 et 9. echo $((RANDOM % 10)) # % : modulo, RANDOM entier entre 0 et 32767 |
Nombres commençant par 0
Les nombres commençant par 0 sont traités en octal
echo $((08+1)) # bash: ((: 08 : valeur trop grande pour la base (le symbole erroné est "08") # bash: 08: value too great for base (error token is "08") # zsh: ok # Forcer le calcul en base 10 : echo $((10#08+1)) v=08 echo $((10#$v+1)) |
# Supprimer les 0 un par un : while [[ $v = 0* ]]; do v=${v#0}; done # Supprimer tous les 0 : v=${v/*(0)/} |
String
Exécuter une commande
cmd="ls" # exécute ls et affiche le résultat eval ${cmd} # exécute ls et tente d'exécuter le premier élément (fichier ou dossier) comme une commande $(${cmd}) # command not found: fichier1 # exécute ls et stocke le résultat dans cmd2 cmd2=$(${cmd}) echo ${cmd2} |
Fichiers, dossiers et chemins
file="/path/filename.ext" # extraire le nom du fichier : filename.ext filename=${file##*/} filename=basename "$file" # extraire le nom du fichier sans l'extension : filename ${filename%.*} # extraire l'extension : ext ${filename##*.} # extraire le chemin : /path ${file%/*} # obtenir le chemin absolu à partir d'un chemin relatif ou d'un lien symbolique readlink -f fichier # concatène le chemin courant avec le nom du fichier: /chemin/courant/fichier |
Concaténation
mot1="une" mot21="bon" mot22="ne" echo "$mot1 $mot21$mot22 concaténation" # une bonne concaténation echo $mot1 $mot21"ne concaténation" mot1="${mot1} bonne concaténation" |
Longueur d'un string
# avec une variable longueur=${#MonString} # longueur +1 echo "AAA" | wc -c # fonctionne avec variables et cosntantes expr lenght "AAA" |
Index, position du premier caractère correspondant
expr index $string $substring # stringZ=abcABC123ABCabc echo $(expr index "$stringZ" 1c) # 3 (c in position 3 matches before 1). |
Extraction d'un sous-string
${string:position:length} ou expr substr $string $position $length # Extracts $substring at beginning of $string, where $substring is a regular expression. expr match "$string" '\($substring\)' ou expr "$string" : '\($substring\)' # Extracts $substring at end of $string, where $substring is a regular expression. expr match "$string" '.*\($substring\)' ou expr "$string" : '.*\($substring\)' # stringZ=abcABC123ABCabc # 123456789...... echo ${stringZ:7} # 23ABCabc # tout à partir du 7ème echo ${stringZ:7:3} # 23A # 3 caractères à partir du 7ème echo ${stringZ: -4} # Cabc # les 4 derniers echo ${stringZ:0:-4} # abcABC123AB # tout sauf les 4 derniers echo $(expr substr $stringZ 4 3) # ABC echo $(expr "$stringZ" : '\(.......\)') # abcABC1 echo $(expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)') # abcABC1 echo $(expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)') # ABCabc |
?, +, {} et | doivent être utilisés avec un backslash : \? \+ \{\} \| |
L'utilisation des parenthèses avec expr match permet de renvoyer un string, sinon un entier est renvoyé égal au nombre de caractères qui correspondent. |
Suppression d'un sous-string
${string#substring} # Supprimer le plus court sous-string en commençant par le début. ${string##substring} # Supprimer le plus long sous-string en commençant par le début. ${string%substring} # Supprimer le plus court sous-string en commençant par la fin. ${string%%substring} # Supprimer le plus long sous-string en commençant par la fin. stringZ=abcABC123ABCabc # |----| shortest # |----------| longest echo ${stringZ#a*C} # 123ABCabc # Supprime au début la plus courte correspondance entre 'a' et 'C'. echo ${stringZ##a*C} # abc # Supprime au début la plus longue correspondance entre 'a' et 'C'. echo ${stringZ%A*c} # abcABC123 # Supprime à la fin la plus courte correspondance entre 'A' et 'c'. echo ${stringZ%%A*c} # abc # Supprime à la fin la plus longue correspondance entre 'A' et 'c'. echo ${stringZ%a*C} # abcABC123ABCabc # Pas de correspondance trouvée par la fin. echo ${stringZ#*C} # 123ABCabc # Supprime tous le début jusqu'au premier 'C'. echo ${stringZ##*C} # abc # Supprime tous le début jusqu'au dernier 'C'. echo ${stringZ%C*} # 123ABCabc # Supprime toute la fin à partir du dernier 'C'. echo ${stringZ%%C*} # abc # Supprime toute la fin à partir du premier 'C'. |
Remplacement d'un sous-string
${string/substring/replacement} # Replace first match of $substring with $replacement. ${string//substring/replacement} # Replace all matches of $substring with $replacement. ${string/#substring/replacement} # Remplace si $string commence par $substring ${string/%substring/replacement} # Remplace si $string se termine par $substring stringZ=abcABC123ABCabc echo ${stringZ/abc/xyz} # xyzABC123ABCabc # Replaces first match of 'abc' with 'xyz'. echo ${stringZ//abc/xyz} # xyzABC123ABCxyz # Replaces all matches of 'abc' with 'xyz'. echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc # Remplace 'abc' avec 'XYZ' au début. echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ # Remplace 'abc' avec 'XYZ' à la fin. echo ${stringZ//\\//} # Remplace tous les '\' par '/'. |
xargs
Permet de construire une liste d'argument.
# par défaut xrags appelle echo avec la liste des arguments echo 1 2 3 4 | xargs # 1 2 3 4 echo 1 2 3 4 | xargs cmd # cmd 1 2 3 4 echo 1 2 3 4 | xargs -n 1 cmd # cmd 1; cmd 2; ... find . -iname "*.mp3" -print0 | xargs -0 -I mp3file mplayer mp3file # -print0 et -0 pour gérer les espaces dans les arguments (noms de fichier) # -I permet de donner un nom à l’argument et de l'utiliser par la suite # supprimer tous les fichiers sauf les 3 plus récents ls -t "${MyPath}" | tail -n +3 | xargs -0 rm -f -- |
-0 Gère les chemins avec des espaces. |
Tableaux / Arrays
Par défaut toutes les valeurs du tableau sont vide. Il n'est pas nécessaire de l'initialiser. Sa taille n'est pas définie.
monTableau=() # déclaration d'un tableau vide monTableau=(valeur0 valeur1 valeur2) # initialisation des valeur 0,1 et 2 monTableau=([0]=valeur0 [10]=valeur10) # initialisation des valeurs 0 et 10 echo ${monTableau[10]} # valeur10 monTableau[5]=valeur5 # changement de la valeur 5 # ajout de valeurX à la fin du tableau monTableau+=('valeurX') # nombre d'éléments du tableau echo ${#monTableau[@]} # tester si le tableau contient un élément if [[ " ${monTableau[@]} " =~ " ${value} " ]]; then # ... fi # parcourir le tableau, utiliser les double quotes pour les éléments contenant des espaces for element in "${monTableau[@]}" do echo $element continue done # afficher le contenu du tableau avec un retour à la ligne après chaque élément printf "%s\n" "${monTableau[@]}" # utiliser le contenu du tableau dans une commande IFS=§ # changer l'internal field separator pour gérer les espaces dans les éléments du tableau rm -f ${monTableau[@]} # stocker le résultat d'une commande dans un tableau IFS=$'\n' read -r -d '' -a my_array \ < <(find '/folder' -maxdepth 1 -type d -printf "%f\n" && printf '\0') |
Associative arrays / Hash tables / Dictionnaires
declare -A map map[key1]="Value 1" echo ${map[key1]} # déclaration en une ligne declare -A map=( [key1]="Value 1" ) for key in "${!map[@]}"; do echo "$key - ${map[$key]}" done |
trap
# stop le script en cas d'erreur set -e # ouverture du trap et définition de la commande à exécuter si le signal EXIT est capturé trap 'echo 333' EXIT echo 111 # l’exécution de 'commande inconnue' va créer une erreur et le script va s'arrêter (set -e) en lançant le signal EXIT # le signal EXIT sera capturé par le trap et la commande associée au trap sera exécutée 'commande inconnue' echo 222 # fermeture du trap, si le signal EXIT est lancé après la fermeture il ne sera pas capturé trap - EXIT echo 444 # sortie # 111 # ./xxx.sh: ligne xx: commande inconnue : commande introuvable # 333 |
EXIT | appel d'«exit» ou sortie du script suite avec l'option «set -e» suite à une erreur |
INT | Ctrl-C from the keyboard |
TERM | kill du processus |
Fonctions
# Les signatures de fonction ne contiennent pas de paramètres Fonction() { $0 # nom du fichier de script avec son chemin tel qu'il a été appelé $1 # argument 1 $@ # liste des tous les arguments $# # nombre d'arguments ($0 compris) local variable_locale="pouet!" echo $FUNCNAME // nom de la fonction: Fonction return 0 # code de retour } # La méthode doit être déclarée avant d'être utilisée Methode arg1 arg2 # code de retour de la méthode (return) echo $? # stocke dans var toutes les valeurs émises par echo depuis Methode var=$(Methode arg1 arg2) |
Par défaut dans bash les variables sont globales. Les variables sont donc accessibles dans et à l'extérieur des fonctions. |
Lire et écrire dans un fichier
# écrire 1 dans « fichier.txt ». Le contenu du fichier est écrasé. Le fichier est créé s'il n'existait pas. echo 1 > fichier.txt # écrire 1 à la suite du contenu existant dans « fichier.txt ». Le fichier est créé s'il n'existait pas. echo 1 >> fichier.txt # lire le contenu de « fichier.txt » et le stocker dans « ma_variable » ma_variable=$(cat fichier.txt) |
extglob option
Permet d'étendre les pattern matching operators:
Operators | Explanations |
---|---|
?(pattern-list) | Matches zero or one occurrence of the given patterns |
*(pattern-list) | Matches zero or more occurrences of the given patterns |
+(pattern-list) | Matches one or more occurrences of the given patterns |
@(pattern-list) | Matches one of the given patterns |
!(pattern-list) | Matches anything except one of the given patterns |
# affiche si l'extglob option est activée ou non shopt extglob # active l'extglob option shopt -s extglob # désactive l'extglob option shopt -u extglob # liste tous les fichiers qui ne se terminent pas par -small.jpg ls !(*-small.jpg) |
Importer / appeler un autre script
# exécution dans le même processus # possibilité d'utiliser les variables et les fonctions . /chemin/vers/un/autre/script.sh source /chemin/vers/un/autre/script.sh . "$(dirname $0)/un_autre_script.sh" # exécution dans un nouveau processus /chemin/vers/un/autre/script.sh bash /chemin/vers/un/autre/script.sh |
Hasher un string
echo -n "mon string" | md5sum echo -n "mon string" | sha512sum |
Astuces
Quitter le script
exit 0 |
0 : succès 1 ou plus : erreur |
Enchaînement de commandes et test code de retour
Si la commande a fonctionnée elle renvoie 0 et le code après les && est éxecuté,
dans le cas contraire la commande n'a pas fonctionné correctement et a renvoyé 1, le code après les || est alors exécuté.
commande && echo ok || echo ko commande if [ $? -ne 0 ]; then echo ko fi |
Chemin absolu du script et de son dossier
$(realpath "$0") $(dirname "$(realpath "$0")") |
True / False
true; echo $? # 0. A successful command returns 0. false; echo $? # 1. An unsuccessful command returns 1. echo $((1 == 1)) # 1. An arithmetic expression returns 1 for true. ok=true if [[ ${ok} == true ]] # avec des entiers : 0=false, tous les autres = true ok=0 if ((ok)) # faux ok=1 if ((ok)) # vrai |
Max
max() { if (( $# != 2 )); then return 1 fi if (( $1 == $2 )); then echo $1 else if (( $1 > $2 )); then echo $1 else echo $2 fi fi return 0 } # utilisation m=$(max 10 5) # m=10 $?=0 m=$(max 10) # m= $?=1 |
Forcer la sortie en anglais
LC_ALL=C macommande |
Relancer le script avec un autre utilisateur
# script lancé avec root # test si c'est bien l'utilisateur 1000 qui à la main # sinon on relance avec l'utilisateur 1000 if [[ $UID -ne 1000 ]]; then su user1000 -c "bash $0" exit $? fi |
Relancer le script avec script pour créer un fichier de log
# on test si la variable restart est définie if [ -z ${restart+x} ]; then export restart=true script_path=$(realpath "$0") dir_path=$(dirname ${script_path}) file_name=$(basename "$0") # on relance le script avec script pour créer un fichier de log script -q -c "${script_path}" "${dir_path}/${file_name%.*}.log" && exit fi # commandes du script ... |
Test si l'utilisateur est root
if [[ $UID -ne 0 ]]; then echo 'Only the root user can run this script.' exit 1 fi |
Lancer une commande avec root sans demande de mot de passe
# un utilisateur autre que root lance la commande suivante en tant que root echo 'mot de passe' | su -c 'ma commande' |
Mise en forme la sortie en colonnes
# mise en colonnes en fonction de la taille du terminal ls -1 | column # beaucoup d'espace entre les colonnes et beaucoup d'espace tout à droite # mise en forme en 3 colonnes # ne dépend pas de la taille du terminal ls -1 | pr -3 -t # beaucoup d'espace entre les colonnes (tabs) # tronque le contenu des colonnes au besoin s'il dépasse # mise en forme en 3 colonnes # ne dépend pas de la taille du terminal # 2 espaces entre chaque colonne ls -1 | pr -3 -t -s'|' | column -t -s'|' |
Alias console
~/.bashrc |
alias ll='ls -alF' # Utilisation des simple quotes dans l'alias alias ds='df -t ext4 -h | grep home | awk '"'"'{ print $4 }'"'"'' # suppression d'un alias unalias ll |
Les alias peuvent être écrit dans un fichier séparé : .bash_aliases
~/.bashrc |
# test si le fichier existe if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi |
Fonctions console
~/.bashrc |
# Utilisation des paramètres via les fonctions function fn() { sudo find / -name ''$1'' ;} # awk et les argument de la fonction function fit() { find . -type f -exec awk -v vawk="$1" '$0 ~ vawk {c++} c>0 {print ARGV[1] ; exit 0 } END { if (! c) {exit 1}}' \{\} \; } # les arguments de fonctions sont $1 ... $9 function xxx() { echo $1 } xxx *.pdf # *.pdf va être transformé en file1.pdf file2.pdf # pour éviter cela xxx "*.pdf" xxx \*.pdf |
Prompt
~/.bashrc |
PS1="\[\e[1;34m\]\w\$(if [[ \$(expr length \"\w\") -gt 50 ]]; then echo \"\n\r\"; else echo \" \"; fi)➭ \[\e[0m\] " |
Codes
- \u : login de l'utilisateur
- \h : le nom de la machine
- \w : le répertoire courant
- \$ : # pour root, sinon $
Couleurs
# Reset Color_Off='\e[0m' # Text Reset # Regular Colors Black='\e[0;30m' # Black Red='\e[0;31m' # Red Green='\e[0;32m' # Green Yellow='\e[0;33m' # Yellow Blue='\e[0;34m' # Blue Purple='\e[0;35m' # Purple Cyan='\e[0;36m' # Cyan White='\e[0;37m' # White # Bold BBlack='\e[1;30m' # Black BRed='\e[1;31m' # Red BGreen='\e[1;32m' # Green BYellow='\e[1;33m' # Yellow BBlue='\e[1;34m' # Blue BPurple='\e[1;35m' # Purple BCyan='\e[1;36m' # Cyan BWhite='\e[1;37m' # White # Underline UBlack='\e[4;30m' # Black URed='\e[4;31m' # Red UGreen='\e[4;32m' # Green UYellow='\e[4;33m' # Yellow UBlue='\e[4;34m' # Blue UPurple='\e[4;35m' # Purple UCyan='\e[4;36m' # Cyan UWhite='\e[4;37m' # White # Background On_Black='\e[40m' # Black On_Red='\e[41m' # Red On_Green='\e[42m' # Green On_Yellow='\e[43m' # Yellow On_Blue='\e[44m' # Blue On_Purple='\e[45m' # Purple On_Cyan='\e[46m' # Cyan On_White='\e[47m' # White # High Intensity IBlack='\e[0;90m' # Black IRed='\e[0;91m' # Red IGreen='\e[0;92m' # Green IYellow='\e[0;93m' # Yellow IBlue='\e[0;94m' # Blue IPurple='\e[0;95m' # Purple ICyan='\e[0;96m' # Cyan IWhite='\e[0;97m' # White # Bold High Intensity BIBlack='\e[1;90m' # Black BIRed='\e[1;91m' # Red BIGreen='\e[1;92m' # Green BIYellow='\e[1;93m' # Yellow BIBlue='\e[1;94m' # Blue BIPurple='\e[1;95m' # Purple BICyan='\e[1;96m' # Cyan BIWhite='\e[1;97m' # White # High Intensity backgrounds On_IBlack='\e[0;100m' # Black On_IRed='\e[0;101m' # Red On_IGreen='\e[0;102m' # Green On_IYellow='\e[0;103m' # Yellow On_IBlue='\e[0;104m' # Blue On_IPurple='\e[0;105m' # Purple On_ICyan='\e[0;106m' # Cyan On_IWhite='\e[0;107m' # White |
Exemples
Lister les dossiers par ordre décroissant de création
ls -t | while read element do [[ -d $element ]] || continue echo $element done # for element in $(ls -t) ne permet pas gérer les noms avec espaces # ls -rt pour trier par ordre croissant de création |
Récupérer le nom du fichier / dossier le plus récent
set +u unset -v latest for element in *; do [[ $element -nt $latest ]] && latest=$element done set -u echo $latest |
Renommer tous les fichiers ayant pour extension "TXT" en "txt"
Par exemple "file.TXT" devient "file1.txt" :
SUFF=TXT suff=txt for i in *.$SUFF do mv -f $i ${i%.$SUFF}.$suff done |
Si aucun fichier *.TXT n'existe, le script a un comportement bizarre. |
Suppression des dossiers .svn
dans le répertoire courant et dans tous les sous-répertoires :
DelDotSvnDirectory() { # liste de tous les sous répertoires. for subDirectory in $(ls -l | grep ^d | awk '{ for (i=9; i<NF; i++) printf $i"°" ; print $NF }') do # Lancement récursif de la méthode dans tous les sous-répertoires. cd "${subDirectory//°/ }" DelDotSvnDirectory done # Suppression du dossier .svn if [ -d ".svn" ]; then rm -rf ./.svn fi cd .. } DelDotSvnDirectory |