Scripts avec Bash

Guillaume Chanel

Remerciements à Jean-Luc Falcone

Cours système d'exploitation by Guillaume Chanel, Jean-Luc Falcone and University of Geneva is licensed under CC BY-NC-SA 4.0

Scripts

Problème réel

  • Aggréger des listes d'emails
  • Supprimer les doublons
  • Les adresses peuvent être écrites avec des casses différentes

Solution possible

A l'aide des commandes shell suivante:
catconcatène plusieurs fichiers
trtransforme les caractères
sorttrie les lignes
uniqrend unique les lignes répétées

$ cat mail1.txt mail2.txt | tr '[A-Z]' '[a-z]' | sort | uniq > result.txt

Les scripts

  • Un script est un fichier texte contenant une séquence de commandes shell
  • Le script peut être exécuté comme une commande

Premier Script

backup1.sh
#Efface les anciens backups
rm -f ~/data/backup/*

#Backup les fichiers .txt et .dat
cp ~/data/*.txt ~/data/*.dat ~/data/backup/
chmod 440 ~/data/backup/*

Exécuter un script (source)

La commande source permet d'éxécuter un script dans le shell actuel

$ source backup.sh

Exécuter un script (#!)

On peut préciser l'interpréteur par défaut du script avec les caractères #! au début du script (prononcer hash-bang, she-bang ou sha-bang):

backup1.sh
#!/bin/bash

#Efface les anciens backups
rm -f ~/data/backup/*

#Backup les fichiers .txt et .dat
cp ~/data/*.txt ~/data/*.dat ~/data/backup/
chmod 440 ~/data/backup/*

Exécuter backup1.sh dans un nouveau processus:

$ chmod u+x backup1.sh
$ ./backup1.sh

DRY

Do not reapeat yourself

Variables

On assigne des variables avec le symbole =.

On accède à la valeur de la variable avec le symbole $:

$ message="Je suis ... "
$ echo message
$ echo $message
$ echo ${message}
$ echo "${message}Guillaume"

Les variables ne sont pas typées.

Exemple de script

backup2.sh
#!/bin/bash

DATA=~/data
BACKUP=$DATA/backup

#Efface les anciens backups
rm -f $BACKUP/*

#Backup les fichiers .txt et .dat
cp $DATA/*.txt $DATA/*.dat $BACKUP
chmod 440 $BACKUP/*

Conditions (if then)

Il existe des structures de contrôle if comme dans la plupart des languages:

if [ EXPRESSION ]; then
    cmd1
    cmd2
    ...
fi

Conditions (if then else)

if [ EXPRESSION ]; then
    cmd1
    cmd2
    ...
else
    cmd10
    cmd11
    ...
fi

Les tests

On peut tester une expression avec la commande test généralement utilisée avec des crochets:

test EXPRESSION
[ EXPRESSION ]

Tests sur les fichiers

-e FILELe fichier FILE existe
-f FILELe fichier FILE existe et est un "vrai" fichier
-d FILELe fichier FILE existe et est un répertoire
-x FILELe fichier FILE existe et est éxécutable
-w FILELe fichier FILE existe et on peut écrire
FILE1 -nt FILE2Le fichier FILE1 est plus récent que le fichier FILE2
FILE1 -ot FILE2Le fichier FILE1 est plus ancien que le fichier FILE2

Exemple de script

backup3.sh
...
DATA=~/data
BACKUP=$DATA/backup

#Si le repertoire existe
if [ -d $BACKUP ]; then
    #Efface les anciens backups
    rm -f $BACKUP/*
else
    #Crée le repetoire
    mkdir -p $BACKUP
fi
...

Autre expressions de test

! EXPRESSIONRetourne vrai si EXPRESSION est fausse
EXPR1 -a EXPR2Retourne vrai si EXPR1 et EXPR2 sont vraies
EXPR1 -o EXPR2Retourne vrai si EXPR1 ou EXPR2 sont vraies
STRING1 = STRING2Retourne vrai si STRING1 égale à STRING2
STRING1 != STRING2Retourne vrai si STRING1 n'est pas égale à STRING2

Boucles (for)

  • Itère sur chaque éléments d'une liste.
  • Les éléments sont séparés par des espaces ou des retours à la ligne
  • Assigne une variable utilisable à l'intérieur de la boucle
  • for VAR in LIST; do
        CMD1 $VAR
        CMD2 $VAR
        ...
    done

Une liste peut être:

  • des éléments séparés par des espaces: for ANIMAL in chat chien oiseau
  • un range: for I in {1..9}
  • une expression représentant un ensemble de fichiers: for FILE in *.txt

Exemple de script

backup4.sh
...
#Backup les fichiers .txt et .dat
for f in $DATA/*.txt $DATA/*.dat; do
    echo "Copie de $f"
    cp $f $BACKUP
    chmod 440 $f
done
...

Substitution de commande

  • Il est souvent intéressant de capturer le résultat d'une commande.

  • Il existe deux formes de syntaxes:

    • `CMD OPTIONS ARGUMENTS`
    • $( CMD OPTIONS ARGUMENTS )
$ echo "Mon nom d'utilisateur est: `whoami`"
$ echo "Mon nom d'utilisateur est: $(whoami)"
$ a=`ls *.sh`
$ a=$(ls *.sh)

Arguments

Il est possible de récupérer les arguments passés à un script en utilisant, les variables $1, $2, $3, etc.

backup5.sh
#!/bin/bash
DATA=$1
BACKUP=$2
...

Usage:

$ ./backup5.sh ~/data ~/data/backup

Fonctions

Les fonctions se définissent de la manière suivante:

function show {
echo "$1 ------ $2"  # $1 et $2 sont les 1er et 2ème paramètres passés à la fonction
}
show foo bar  # appel à la fonction
Remarques

On peut accéder aux arguments des fonctions en utilisant: $1, $2, etc. Les arguments du script sont cachés.

Fonction et case

function extract() {
    if [ -f $1 ] ; then
        case $1 in
            *.tar.gz) tar xvzf $1  ;;
            *.bz2)    bunzip2 $1   ;;
            *.rar)    unrar x $1   ;;
            *.gz)     gunzip $1    ;;
            *.tgz)    tar xvzf $1  ;;
            *.zip)    unzip $1     ;;
            *)        echo "'$1' cannot be extracted" ;;
        esac
    else
        echo "'$1' is not a valid file"
    fi
}

Autres sujets

  • Opérations arithmétiques
  • Tableaux
  • Variables définies par défaut
  • Règles pour les guillemets (quotation)


Bash beginners guide

Ryan's bash scripting tutorial

Configurer BASH

Fichiers de configurations

Bash utilise plusieurs fichiers cachés à la racine du home pour obtenir une configuration:

.bashrcexécuté à chaque nouveau shell (non-login)
.bash_profileshell de login uniquement.
.bash_logoutexécuté lorsqu'on quitte un shell de login

Shell de login (.bash_profile)

  • Les shells de logins sont ceux pour lequels on doit s'authentifier:
    • Connexion à distance
    • Console virtuelle (tty)
  • Un terminal lancé depuis l'interface graphique n'est pas un shell de login
  • La pratique actuelle est d'appeler .bashrc depuis .bash_profile (automatique sous Mac).
.bash_profile
...
if [ -f ~/.bashrc]; then
    source ~/.bashrc
fi
...

Configuration du shell (.bashrc)

Habituellement, on utilise .bashrc pour définir les éléments suivants:

  • Variables d'environement
  • Alias
  • Permisissions par défaut
  • Comportement de Bash

Variables d'environement (export)

  • Variables accessibles aux processus
  • Tous les langages de programmation (sérieux) permettent d'y accéder.
  • Les processus enfants héritent des variables d'environement du parent.
  • On accède à leur valeur avec un $ (comme une variable normale).
  • On les définit avec export:
$ export VAR1="hello world"
$ echo $VAR1

Variables d'environement standard

$PATHchemin d'accès
$HOMErépertoire Home
$LANGLanguage par défaut
$DISPLAYServeur graphique
$PS1Prompt
$HOSTNAMENom de la machine

Le chemin par défaut

  • Le chemin d'accès indique où chercher les exécutables.
  • La variable d'environement $PATH définit le chemin par défaut.
  • Si l'éxécutable n'est pas dans le chemin par défaut, il faut préciser le chemin complet.
Exemple de chemin par défaut
/home/falcone/bin:/usr/lib/lightdm/lightdm:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:
/sbin:/bin:/usr/games
Dans quel fichier ? .bashrc ou .bash_profile ?
export PATH=~/bin:$PATH

Les alias

  • On peut définir des alias pour raccourcir l'invocation de commandes et de leurs arguments
  • On peut accéder à la commande originale en utilisant un backslash.
  • La commande alias seule permet d'afficher tous les alias.
Dans .bashrc
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias ls='ls --color=auto'
alias ll='ls -lh'
alias la='ll -a'

Permissions par défaut (umask)

  • Il est possible de spécifier les permissions par défaut grâce à la commande umask.
  • Syntaxe: umask [permissions]
    • Les permissions sont les permissions à enlever en octal.
  • Utilisée seule, umask donne sa valeur actuelle.
Exemple

Par défaut on veut:

  • retirer au groupe le droit d'écrire
  • retirer aux autres tous les droits
umask 027

Commandes utiles

awk '{print $n}'selectioner la n ème colonne.
basename <FILE>récupère le nom du fichier (sans le chemin)
dirname <FILE>récupère le chemin d'un fichier
sed s/JPEG/jpg/remplace 'JPEG' par 'jpeg'
uname -nretourne le nom de la machine
cut -c m-nextrait les caractères de m à n de chaque ligne
sed '1d'ommet la première ligne

Ressources

  1. Livres

    • Unix Power Tools 3rd Edition, 2002, O'Reilly.
  2. Liens