« Bash » : différence entre les versions

De Banane Atomic
Aller à la navigationAller à la recherche
 
(25 versions intermédiaires par le même utilisateur non affichées)
Ligne 5 : Ligne 5 :
= Début de fichier =
= Début de fichier =
<kode lang="bash">
<kode lang="bash">
#!/usr/bin/bash           # spécifier quel shell doit être utilisé
# spécifie quel shell doit être utilisé
#!/usr/bin/bash


set -e
set -e
Ligne 16 : 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) échoue (retourne une valeur différente de true)
# 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 95 : Ligne 96 :
"${ARGS[@]}" # tous les arguments
"${ARGS[@]}" # tous les arguments
"${ARGS[0]}" # premier argument
"${ARGS[0]}" # premier argument
</kode>
== [https://gist.github.com/cosimo/3760587 GNU getopt] ==
<kode lang='bash'>
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
</kode>
</kode>


Ligne 141 : Ligne 183 :
commande 2>&1
commande 2>&1


# redirige stdout et stderr vers un fichier
# redirige stdout et stderr vers file.log
commande >fichier 2>&1
# 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 le terminal et stdout vers un fichier
commande 2>&1 >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
# redirige stderr vers stdout (terminal) et écrit stdout (et stderr) vers un fichier
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.
script -q -c 'commande' fichier
script -q -c 'commande' fichier
</kode>
</kode>
{{warn | <tt>commande >fichier 2>&1</tt> redirige stdout vers fichier, puis stderr vers stdout donc vers fichier<br /><tt>commande 2>&1 >fichier</tt> redirige stderr vers stdout donc vers le terminal, puis stdout vers fichier}}


= Variables =
= Variables =
Ligne 162 : Ligne 214 :


# affichage du contenu d'une variable
# affichage du contenu d'une variable
echo $ma_variable      // valeur
echo $ma_variable      # valeur
echo $ma_variable1    //
echo $ma_variable1    #
echo ${ma_variable}1  // valeur1
echo ${ma_variable}1  # valeur1


# par défaut toutes les variables sont globales
# par défaut toutes les variables sont globales
Ligne 281 : 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>


= if / else =
= if / else =
<kode lang="bash">
<kode lang="bash">
if expression; then
if (expression); then
     echo 1
     echo 1
elif ! expression; then
elif ! (expression); then
     echo 2
     echo 2
else
else
Ligne 294 : Ligne 349 :


# en une ligne
# en une ligne
if [ true ]; then echo 1; echo 2; else echo 3; fi
if [ expression ]; then echo 1; echo 2; else echo 3; fi
</kode>
</kode>


= [[ ]] =
= [[ ]] =
<kode lang=bash>
<kode lang=bash>
# commande exécutée si test est vrai
# if expression is true then execute commande
[[ test ]] && commande
[[ expression ]] && command


# commande exécutée si test est faux
# if expression is false then execute commande
[[ test ]] || commande
[[ expression ]] || command
</kode>
 
== Booleans ==
<kode lang=bash>
var1=false
 
if $var1
if [ $var1 = true ]
if [[ $var1 = true ]]
</kode>
</kode>


Ligne 311 : Ligne 375 :
if [[ $1 != $2 ]]  # vrai si le string contenu dans $1 n'est pas 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
</kode>
</kode>
{{warn | Do not use the {{boxx|$<nowiki>{var}</nowiki>}} form to call the variable, use {{boxx|$var}} instead.}}


== [http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html Expressions rationnelles (regex) et patrons de correspondance] ==
== [http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html Expressions rationnelles (regex) et patrons de correspondance] ==
Ligne 335 : Ligne 400 :
fi
fi
</kode>
</kode>
{{info | Escape the following characters {{boxx|( ) .}}}}


== Entiers ==
== Entiers ==
Ligne 619 : Ligne 686 :
IFS=§  # changer l'internal field separator pour gérer les espaces dans les éléments du tableau
IFS=§  # changer l'internal field separator pour gérer les espaces dans les éléments du tableau
rm -f ${monTableau[@]}
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')
</kode>
</kode>


Ligne 896 : Ligne 967 :
# Utilisation des simple quotes dans l'alias
# Utilisation des simple quotes dans l'alias
alias ds='df -t ext4 -h | grep home | awk '"'"'{ print $4 }'"'"''
alias ds='df -t ext4 -h | grep home | awk '"'"'{ print $4 }'"'"''
# suppression d'un alias
unalias ll
</filebox>
</filebox>


Les alias peuvent être écrit dans un fichier séparé : <tt>.bash_aliases</tt>
Les alias peuvent être écrit dans un fichier séparé : {{boxx|.bash_aliases}}
<filebox fn=~/.bashrc lang="bash">
<filebox fn=~/.bashrc lang="bash">
# test si le fichier existe
# test si le fichier existe

Dernière version du 16 juin 2024 à 13:07

Liens

Début de fichier

Bash.svg
# spécifie quel shell doit être utilisé
#!/usr/bin/bash

set -e
set -o pipefail
set -u

wd="$(dirname "$(realpath "$0")")"

Options Bash

Bash.svg
# 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

Bash.svg
# 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.

Bash.svg
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

Bash.svg
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
Bash.svg
# 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

Bash.svg
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

Bash.svg
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

Bash.svg
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
Bash.svg
# 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

Bash.svg
# 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
Bash.svg
# 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

Bash.svg
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.

Bash.svg
v=1   # 1
v+=1  # 11

# declare v comme un entier
declare -i v

v=1   # 1
v+=1  # 2

For

Bash.svg
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

Bash.svg
# 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

Bash.svg
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

[[ ]]

Bash.svg
# if expression is true then execute commande
[[ expression ]] && command

# if expression is false then execute commande
[[ expression ]] || command

Booleans

Bash.svg
var1=false

if $var1
if [ $var1 = true ]
if [[ $var1 = true ]]

Strings

Bash.svg
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

Bash.svg
# 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

Bash.svg
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 (( ))
Bash.svg
if (($1>$2))

Opérateurs ET, OU

Bash.svg
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

Bash.svg
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 [ ]

Bash.svg
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

Bash.svg
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

Bash.svg
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

Bash.svg
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))
Bash.svg
# 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

Bash.svg
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

Bash.svg
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

Bash.svg
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

Bash.svg
# 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

Bash.svg
expr index $string $substring

# stringZ=abcABC123ABCabc
echo $(expr index "$stringZ" 1c)   # 3 (c in position 3 matches before 1).

Extraction d'un sous-string

Bash.svg
${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

Bash.svg
${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

Bash.svg
${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.

Bash.svg
# 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.

Bash.svg
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

Bash.svg
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

Bash.svg
# 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
Signaux
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

Bash.svg
# 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

Bash.svg
# é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
Bash.svg
# 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

Bash.svg
# 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

Bash.svg
echo -n "mon string" | md5sum
echo -n "mon string" | sha512sum

Free Password Hash Cracker

Astuces

Quitter le script

Bash.svg
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é.

Bash.svg
commande && echo ok || echo ko

commande
if [ $? -ne 0 ]; then
    echo ko
fi

Chemin absolu du script et de son dossier

Bash.svg
$(realpath "$0")
$(dirname "$(realpath "$0")")

True / False

Bash.svg
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

Bash.svg
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

Bash.svg
LC_ALL=C macommande

Relancer le script avec un autre utilisateur

Bash.svg
# 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

Bash.svg
# 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

Bash.svg
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

Bash.svg
# 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

Bash.svg
# 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

Bash.svg
# 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

Bash.svg
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

Bash.svg
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" :

Bash.svg
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 :

Bash.svg
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