Tests de fichiers, structures conditionnelles et boucles en Bash

Compléments sur la commande test

Opérations relatives aux fichiers

Vérifieer si deux fichiers partagent le même inode (ce sont des liens physiques)

if [ "$f1" -ef "$f2" ]

Déterminer lequel des deux fichiers est le plus récent

FICHIER1 -nt FICHIER2

FICHIER1 est plus récent (date de modification) que FICHIER2

Déterminer lequel des deux fichiers est le plus ancien

FICHIER1 -ot FICHIER2

FICHIER1 est plus ancien que FICHIER2

Vérifier que le fichier existe et qu'il s'agit d'un périphérique bloc

-b FICHIER

Vérifier que le fichier existe et qu'il s'agit d'un périphérique caractère

-c FICHIER

Vérifier que le fichier existe et qu'il s'agit d'un répertoire

-d FICHIER

Vérifier que le fichier existe

-e FICHIER

Vérifier que le fichier existe et qu'il s'agit d'un fichier ordinaire

-f FICHIER

Vérifier que le fichier existe et qu'il s'agit d'un lien symbolique

-h FICHIER / -L FICHIER

Vérifier que le fichier existe et qu'il s'agit d'un tube nommé

-p FICHIER

Vérifier que le fichier existe et qu'il s'agit d'une socket

-S FICHIER

Vérifier que le fichier existe et qu'il n'est pas vide

-s FICHIER

Vérifier que le fichier existe et qu'il dispose des droits de lecture

-r FICHIER

Vérifier que le fichier existe et qu'il dispose des droits d'écriture

-w FICHIER

Vérifier que le fichier existe et qu'il dispose des droits d'exécution

-x FICHIER

Exercice :

Saisir un nom de fichier et déterminer s'il existe.

S'il n'existe pas, l'indiquer puis le créer.

S'il existe, identifier son type parmi b, c, d, L, s, p, f et l'afficher.

S'il s'agit d'un répertoire, lister tous les fichiers .sh qu'il contient.

S'il s'agit d'un fichier ordinaire, vérifier les droits d'écriture ; si ceux-ci sont absents, ajouter les permissions lecture, écriture et exécution.

Écrire ensuite la chaîne « hello » dans le fichier.

La structure case...esac

case $variable in
    motif1)
        instructions
        ;;
    motif2)
        instructions
        ;;
    ...
    *)
        instructions_par_defaut
        ;;
esac
  1. La variable joue le rôle d'une expression de type switch.
  2. Chaque motif correspond à une valeur possible de cette variable.

Formats aceptés pour un motif :

hello)
'hello')
"hello")

Les motifs peuvent être reliés par un OU bit à bit :

A|a)

Ils peuvent également combiner des métacaractères : *, ?, []

h*)
h?)
9[0-9]|100)
  1. Le ;; joue le rôle du break d'un switch : il clôt la branche courante. Le dernier est facultatif, tous les autres sont obligatoires.
  2. *) capture tous les cas non couverts par les motifs précédents.

Exercice : saisir une note et déterminer la mention correspondante avec case...esac.

90-100 A / 70-89 B / 60-69 C / 0-59 D

Exrecice : saisir une expression et implémenter les opérateurs + - * / % avec case...esac.

Les boucles du shell

Le shell propose les boucles for, while et select...in.

while

Format :

while [ expression ]   # ou while test expression
do
    corps_de_boucle
done

Tant que l'expression est vraie, la boucle s'exécute ; dès qu'elle devient fausse, la boucle se termine.

Boucle infinie :

while [ 1 ]    # ou while true

Exercices :

Calculer la factorielle de n.

Saisir un tableau, afficher chaque élément avec une boucle et calculer la moyenne.

Saisir un nombre et calculer la somme de ses chiffres.

Saisir une chaîne et l'inverser.

for

Première syntaxe (proche du C, ne permet pas d'itérer sur des éléments non contigus) :

for (( expression1 ; expression2 ; expression3 ))
do
    corps_de_boucle
done

Exercice : déclarer un tableau, l'initialiser et l'afficher à l'aide d'une boucle.

Exercice : déclarer un tableau contenant les fichiers et dossiers de /home/ubuntu/ et l'afficher en boucle.

Deuxième syntaxe (proche de Python, plus polyvalente) :

for variable in liste_de_valeurs
do
    corps_de_boucle
done

La liste est découpée sur les espaces par défaut.

Elle peut être composée de constantes :

for i in 1 2 3 4 5

Parcourir les éléments d'un tableau :

for element in ${monTableau[*]}

La liste peut aussi être une séquence ordonnée produite par seq :

$(seq debut pas fin)
`seq debut pas fin`

Ou par une expansion d'accolades (les deux bornes doivent être des constantes) :

{1..10}

Exercices :

Saisir un tableau et déterminer la valeur maximale.

Saisir un entier et déterminer avec une boucle s'il s'agit d'un nombre parfait (somme de ses diviseurs propres égale au nombre).

Afficher un triangle de chiffres avec for.

select...in

Cette boucle renforce l'interactivité entre le terminal et l'utilisateur.

select variable in liste_de_valeurs
do
    instructions
done

Les éléments de la liste sont assignés successivement à la variable, un menu est affiché, et l'utilisateur choisit par son numéro. Si la saisie ne correspond à aucune entrée, la variable reçoit une valeur vide ; si l'utilisateur appuie simplement sur Entrée, le menu est réaffiché.

Instructions de saut

break

break n

n=1 : facultatif, sort de la boucle courante.
n différent de 1 : obligatoire, sort des n niveaux de boucles imbriquées.

continue

continue n

n=1 : facultatif, passe à l'itération suivante de la boucle courante.
n différent de 1 : obligatoire, agit sur les n niveaux de boucles imbriquées.

Exercices

1. Déclarer un tableau contenant les fichiers et dossiers de /home/ubuntu/, puis compter séparément le nombre de fichiers et de répertoires à l'aide d'une boucle.

#!/bin/bash

contenu=($(ls /home/ubuntu))
total=${#contenu[*]}
nbFichiers=0
nbDossiers=0

for (( indice=0; indice<total; indice++ ))
do
    entree=${contenu[indice]}
    echo "$entree"
    if [ -f "$entree" ]
    then
        ((nbFichiers++))
    elif [ -d "$entree" ]
    then
        ((nbDossiers++))
    fi
done

echo "Fichiers : $nbFichiers | Dossiers : $nbDossiers"

2. Demander un identifiant et un mot de passe (saisie masquée), avec trois tentatives autorisées. Identifiant par défaut : admin, mot de passe : 1234, solde du compte : 10000.

En cas d'échec, afficher un message indiquant le numéro de la tentative et le nombre d'essais restants.

Après trois échecs, le compte est verrouillé.

En cas de succès, afficher le menu de la banque :

  1. Consulter le solde
  2. Retirer de l'argent
  3. Déposer de l'argent

Option 1 : afficher le solde courant.
Option 2 : demander le montant. Si celui-ci dépasse le solde, indiquer que le solde est insuffisant. Sinon, effectuer le retrait et afficher le nouveau solde.
Option 3 : demander le montant, l'ajouter au solde et afficher le nouveau solde.

#!/bin/bash

solde=10000
utilisateurAttendu="admin"
motDePasseAttendu="1234"
essais=0
verrouille=0

while [ $verrouille -eq 0 ]
do
    read -p "Identifiant : " saisieUser
    read -s -p "Mot de passe : " saisiePass
    echo

    if [ "$saisieUser" = "$utilisateurAttendu" ] && [ "$saisiePass" = "$motDePasseAttendu" ]
    then
        echo "Connexion réussie"
        quitter=0
        while [ $quitter -eq 0 ]
        do
            select choix in "Solde" "Retrait" "Dépôt" "Quitter"
            do
                case $choix in
                    "Solde")
                        echo "Solde actuel : $solde"
                        ;;
                    "Retrait")
                        read -p "Montant à retirer : " montant
                        if [ $montant -gt $solde ]
                        then
                            echo "Solde insuffisant, veuillez réessayer"
                        else
                            solde=$((solde - montant))
                            echo "Retrait effectué. Solde restant : $solde"
                        fi
                        ;;
                    "Dépôt")
                        read -p "Montant à déposer : " montant
                        solde=$((solde + montant))
                        echo "Dépôt effectué. Nouveau solde : $solde"
                        ;;
                    "Quitter")
                        quitter=1
                        ;;
                    *)
                        echo "Choix invalide"
                        ;;
                esac
                break
            done
        done
    else
        essais=$((essais + 1))
        restants=$((3 - essais))
        if [ $restants -eq 0 ]
        then
            echo "Troisième échec, le compte est verrouillé"
            verrouille=1
        else
            echo "Échec de la tentative $essais, il reste $restants essai(s)"
        fi
    fi
done

3. Saisir un tableau et le trier par la méthode du tri à bulles.

#!/bin/bash

read -p "Saisir une liste de nombres : " -a nombres
taille=${#nombres[*]}

for (( passe=0; passe<taille-1; passe++ ))
do
    for (( position=0; position<taille-passe-1; position++ ))
    do
        voisin=$((position + 1))
        if [ ${nombres[position]} -gt ${nombres[voisin]} ]
        then
            tampon=${nombres[position]}
            nombres[position]=${nombres[voisin]}
            nombres[voisin]=$tampon
        fi
    done
done

echo "Tableau trié : ${nombres[*]}"

Étiquettes: bash shell-scripting file-testing case-statement boucles

Publié le 18 septembre à 02h30