MON 3 : Bash

Tags :
  • MON
  • 2022-2023
  • temps 2
  • bash
Auteurs :
  • Thomas Pont

Bash : utilisation d'une interface en ligne de commande

Introduction

Ce MON est destiné à des débutants en Bash. En effet, avant de débuter ce travail je n'avais que peu de connaissances sur le sujet.

Bash (ou Bourne-Again Shell) est un interpréteur en ligne de commande. C’est un Shell : il reçoit des commandes informatiques d’un utilisateur et les envoie au système d’exploitation pour que ce dernier les exécute. Il permet d’utiliser son ordinateur de façon efficace et de réaliser des opérations complexes très rapidement. Il s’agit d’une interface en ligne de commande ou CLI (“Command Line Interface”). L’utilisateur est face à un terminal dans lequel il entre ses lignes de commandes. La plupart des utilisateurs utilisent une interface graphique ou GUI (“Graphical User Interface”). C’est l’utilisation la plus classique de son ordinateur : avec l’accueil, le bureau, les icônes,... Même si une CLI peut être plus complexe à maîtriser et moins intuitive, elle est plus puissante qu’une GUI. Par ailleurs Bash fonctionne généralement en commande synchrone. Cela signifie que les lignes de commande sont lues et exécutées une par une.

Comment faire du Bash ?

Bash est conçu pour être utilisé sur un environnement Linux ou MacOS. On peut également en faire sur Windows mais, sans interpréteur, certaines fonctions peuvent être limitées. Pour ce MON, j’ai utilisé Bash sur un système Linux en me connectant à mon compte Centrale. Pour cela j’ai lancé la commande suivante dans un terminal Windows Powershell:

ssh tpont@sas1.ec-m.fr

En entrant son mot de passe Centrale, on se connecte sur son environnement de travail Centrale.

Lorsqu’on est connecté, on peut voir que sa ligne de commande commence par :

[tpont@sas1 ~]$

Dans un premier lieu (avant le ~), il s’agit du nom d’utilisateur. Le signe “~” en fin de ligne indique que l’on se situe dans le dossier home. Le signe “$” quant à lui signifie qu’on est connecté en tant qu’utilisateur classique. Afin d’apprendre les bases de Bash, j’ai suivi le cours suivant : Apprendre à utiliser le shell Bash - Pierre Giraud.

Les principales commandes

Bash s’effectue en ligne de commande. Pour cela, il faut connaître les différentes commandes existantes. Sur certaines commandes, on peut rajouter des options. Cela permet d’avoir plus de fonctionnalités que la commande de base. Elles sont matérialisées par des "-".

Principales commandes

Les principales commandes en Bash sont les suivantes :

Par exemple,

[tpont@sas1 ~]$cd Documents

permet de se déplacer dans le dossier Documents. Ceci est matérialisé par l’invite de commande qui est désormais :

[tpont@sas1 ~/Documents]$

La commande cd .. permet de revenir dans le dossier parent de là où l'on se trouve.

cp fichier1 fichier2

copie fichier1 et nomme la copie fichier2. Si fichier2 existait déjà, la précédente version en est écrasée.

cp fichier1 répertoire1

copie fichier1 et met cette copie dans répertoire1. On peut copier plusieurs fichiers dans un répertoire en mettant leurs noms les uns à la suite des autres.

Enfin, pour copier répertoire1 et mettre une copie dans un répertoire nommé répertoire2, on utilise la commande :

cp -R répertoire1 répertoire2

Comme précédemment si répertoire2 n'existait pas il est créé. Sinon, le répértoire2 déjà existant est écrasé.

Attention aux espaces

Si le nom du document ou du dossier comporte des espaces, pour que la commande puisse bien être interprétée, il faut mettre des \ avant les espaces ou des “ ” ou encore des ‘ ’ autour du nom du fichier ou du dossier. Par exemple :

cp “ mon document.txt” Dossier
mv fichier1.txt fichier.txt

renomme le fichier "fichier1.txt" en "fichier.txt".

mv fichier1.txt répertoire1

déplace le fichier "fichier1.txt" dans répertoire1. Cette commande fonctionne de manière identique pour déplacer un répertoire dans un autre répertoire.

rm fichier1.txt

supprime "fichier1.txt" de manière définitive.

rm -r répertoire1

supprime le répertoire "répertoire1" et ce qu'il contient de manière définitive.

mkdir nouveau_répertoire

crée un nouveau répertoire intitulé "nouveau_répertoire".

Les extensions

Les commandes ci-dessus permettent de naviguer dans les fichiers et les répertoires. Cependant, ceci est également possible avec l'interface graphique. Mais, Bash permet également d'utiliser des extensions. Ceci permet de réaliser des tâches plus complexes rapidement. C'est par exemple le cas de l'utilisation de métacaractères.

Ainsi on peut sélectionner des fichiers et/ou des répertoires à l'aide de ces métacaractères.

Par exemple, la commande

cp *.txt Dossier

permet de copier tous les fichiers en .txt dans le répertoire Dossier.

L'accolade {} permet de réaliser une même action sur des motifs qui se répètent. Par exemple :

mkdir répertoire-{1,2,3,4}

permet de créer quatre répertoires numérotés de 1 à 4.

Par ailleurs, on peut à l'aide de la substitution de commande écrire plusieurs commandes sur une seule ligne.

mkdir $(seq 1 5)

permet d'engendrer une séquence des chiffres de 1 à 5 et à l'aide de la substitution de commandes de créer des répertoires numérotés de 1 à 5.

Projet en Bash

Après avoir vu les commandes élémentaires et les avoir testées pour bien les comprendre, on peut réaliser un projet en Bash qui peut être pratique pour effectuer différentes tâches.

Création d'un script en Bash

Pour lancer un script faisant appel à des commandes, on peut créer un script en Bash. La commande suivante permet de le faire :

cd $HOME && touch script.sh && chmod +x script.sh

Ceci permet de se placer dans le dossier home, de créer un script "script.sh" et de l'ajouter dans la liste des scripts exécutables. Un script Bash doit commencer par :

#!/bin/bash'

pour pouvoir être exécuté correctement. On peut écrire un script qui affiche "Hello world !" quand on le lance en utilisant la commande nano.

#!/bin/bash'
echo "Hello World !"

Le script ci-dessus affiche "Hello World !" quand on le lance, soit quand on effectue ./script.sh dans l'invite de commande.

Scripts plus complexes

L'idée est alors de réaliser des scripts plus compliqués permettant d'effectuer des tâches complexes. Une première idée est de réaliser un script qui cherchera et affichera toutes les occurrences d'un mot dans les fichiers texte d'un répertoire en indiquant leurs positions.

Recherche d'un mot clé dans les fichiers d'un répertoire

Ce script doit prendre en entrée deux arguments : un répertoire où chercher le mot clé et le mot clé.

On commence par vérifier que notre script prend bien deux arguments en entrée puis on cherche le mot clé dans les documents du répertoire.

if [ "$#" -ne 2 ]; then
    echo "Il n'y a pas le bon nombre d'argument. Veuillez entrer, un répertoire et un mot clé."
    exit 1
fi

fichiers=$(ls $1)

for fichier in $fichiers; do
  grep -n "$2" "$1/$file"
done

Ce script permet dans un premier temps de vérifier que le script prend bien deux arguments en entrée. En effet $# permet de connaître le nombre d'argument. Ensuite, la commande grep -n permet de renvoyer les lignes d'un document où un mot apparaît

Attention aux opérateurs de comparaison

Attention, pour la comparaison d'entiers, les opérateurs de comparaisons peuvent être retrouvés ici.

Gestionnaire de tâches

L'objectif est de créer un gestionnaire de tâches. Ce gestionnaire stockera une liste de tâches dans un fichier texte et permettra de stocker leur état (à faire, fait).

Pour ce faire, on crée un script gestion.sh et un fichier texte tache.txt. On a besoin de plusieurs commandes pour faire fonctionner ce gestionnaire :

#!/bin/bash

case "$1" in
        "add")
                # code pour ajouter une tache
                if [ "$#" -eq 1 ]; then
                        echo "La tâche à ajouter ne peut pas être vide"
                        exit 1
                fi
                echo " $2" >> tache.txt
                echo "Tâche ajoutée"
                ;;
        "done")
                # code pour marquer une tâche effectué
                if [ "$#" -eq 1 ]; then
                        echo "Vous n'avez pas entré de tâche à valider"
                        exit 1
                fi

                if ! grep -iq "$2" tache.txt; then
                        echo "Cette tâche n'existe pas"
                        exit 1
                fi

                tache=$2
                #awk '/$2/{echo NR;exit}' tache.txt >> temporaire.txt
                #index=cat temporaire.txt
                #awk '/$2/{index_tache = NR;exit}' tache.txt

                if sed -n '$3p' tache.txt | grep -q '^X'; then
                        echo "La tâche a déjà été terminée"
                        exit 1
                fi

                sed -i .txt '$3s/^/X /' tache.txt
                echo "Tache marquée comme faite";;
        "undo")
                # code pour marquer une tâche non faite
                if [ "$#" -eq 1 ]; then
                        echo "Vous n'avez pas entré de tâche."
                        exit 1
                fi

                if ! grep -iq "$2" tache.txt; then
                        echo "Cette tâche n'existe pas"
                        exit 1
                fi

                if ! sed -n '$3p' tache.txt | grep -q '^X'; then
                        echo "La tâhe n'est pas terminée"
                        exit 1
                fi

                sed -i .txt '$3s/^X //' tache.txt
                echo "Tâche marquée comme non finie"
                ;;
esac

Ce code permet d'ajouter une tâche, de marquer une tâche comme faite et comme non faite.

Il possède néanmoins un problème. Je n'arrive pas à récupérer le numéro de ligne d'un texte dans mon script. J'arrive à le faire directement dans l'invite de commande grâce à la commande suivante :

awk '/$2/{echo NR;exit}' tache.txt >> temporaire.txt

Cela permet de stocker la valeur dans un fichier temporaire et de la récupérer grâce à la commande cat. Ainsi, il est ici nécessaire d'entrer la ligne de la tâche pour les commandes done et undo en troisième paramètre.

Autres ressources utilisées