Newer
Older
cours-unix-shell / src / shell / tp.md
# Travaux pratiques - Shell - UNIX

> ⚠️ Tous les shells qui seront créés par la suite devront avoir le droit
> d'exécution correctement positionné, au moins pour leur propriétaire.

## Recherche d'information sur un utilisateur

1. Écrivez un script shell `infouser.sh` qui permette de chercher si un
   utilisateur d'un nom donné existe sur votre machine, en affichant sa
   référence complète (c'est-à-dire sans aucun filtrage).  
   Le nom recherché sera passé comme paramètre au shell.  
   La recherche portera dans le fichier `/etc/passwd`.  
   > 📗 Utilisez la commande `grep`. Cet exercice a pour objectif de construire
   > un script shell, pas d'y faire quelque chose de compliqué.

   > ⚠️ Comme d'habitude quand on veut traiter un fichier, il vaut mieux
   > visionner son contenu, avant de vouloir l'exploiter (`less /etc/passwd`).

    <details>
      <summary>Voir la solution</summary>

    ```bash
    #!/usr/bin/env bash
    grep $1 /etc/passwd
    ```

    </detais>

2. Modifiez ce shell pour qu'il teste si le nombre de paramètres est bien 1.  
   En cas d'erreur (aucun paramètre ou plus d'un), un message sera affiché
   expliquant la bonne syntaxe à suivre.

    <details>
    <summary>Voir la solution</summary>

    ```bash
    #!/usr/bin/env bash

    if test $# -ne 1
    then
      echo Mauvais nombre de parametres.
      echo
      echo Usage: $0 uid
      exit 1
    fi

    grep $1 /etc/passwd
    ```

    </details>

## Quelques manipulations sur un corpus XML

Pour cette partie du TP, il vous faut d'abord récupérer le corpus suivant :
[`francis.exodic.xml`](./francis.exodic.xml)

Ce fichier contient 20 notices en XML Exodic, dans une forme indentée, son
exploration préparatoire est conseillée.

1. Écrivez un script shell qui compte le nombre de notices, en passant le nom de
   fichier en paramètre.  
    L'élément racine se nomme `exodic`.

    <details>
    <summary>Voir la solution</summary>

    ```bash
    #!/usr/bin/env bash

    if test $# -ne 1
    then
      echo Mauvais nombre de parametres.
      echo
      echo Usage: $0 fichier
      exit 1
    fi

    NB_NOTICES=$(cat $1 | grep "<exodic " | wc -l)

    echo Nombre de notices dans $1: ${NB_NOTICES}
    ```

    </details>

2. Modifiez le shell précédent pour qu'il teste en plus l'existence du fichier
   demandé avant traitement, puis pour qu'il sorte les résultats dans un fichier
   nommé `resultats.txt`.

    <details>
    <summary>Voir la solution</summary>

    ```bash
    #!/usr/bin/env bash

    if test $# -ne 1
    then
      echo Mauvais nombre de parametres.
      echo
      echo Usage: $0 fichier
      exit 1
    fi

    if test ! -f $1
    then
      echo $1 "n'existe pas (ou n'est pas un fichier)."
      exit 2
    fi

    NB_NOTICES=$(cat $1 | grep "<exodic " | wc -l)

    echo Nombre de notices dans $1: ${NB_NOTICES} > resultats.txt
    ```

    > ⚠️ Cette fois, on a mis la chaîne contenant les apostrophes (caractère
    > spécial) entre guillemets pour les banaliser.

    </details>

3. Installer et parcourir des fichiers dublin core d'un arbre de répertoires
    pour afficher le type de document des notices qui y sont présentes.  
    Il faut d'abord récupérer le fichier [`data_dc.tar.gz`](./data_dc.tar.gz).

    Créez le répertoire `Formation/TP_dc`.  
    Déplacez-vous dans ce répertoire.  
    C'est là que vous sauvegarderez votre script shell.  

    Votre shell devra décompresser l'archive du fichier tar sous
    `Formation/TP_dc`.  
    Cela donnera un répertoire `dc` contenant 5 répertoires nommés de 1 à 5.  
    Ces sous-répertoires contiennent chacun un fichier `dublin_core.xml` avec
    une seule notice (qu'il est conseillé d'aller regarder).

    Ces opérations réalisées, la suite du shell devra chercher le type de
    document de chaque notice, identifiable avec `dcvalue element="type"`.  
    Cette information trouvée, les résultats seront écrits dans le fichier
    `typesDC.txt`.

    > 💡 Après la décompression de l'archive, on trouvera dans ce shell:
    >
    > - une boucle
    > - l'utilisation de `grep`
    > - une redirection
    > - pas de gestion de paramètres

    <details>
    <summary>Voir la solution</summary>

    ```bash
    #!/usr/bin/env bash

    # En étant dans le repertoire Formation/TP_dc
    gunzip data_dc.tar.gz
    tar -xvf data_dc.tar

    for FILE in dc/*/*.xml
    do
        cat $FILE | grep 'dcvalue element="type"' >> typesDC.txt
    done
    ```

    > ⚠️ Cette fois, on a mis la chaîne contenant les guillemets (caractère spécial)
    > entre apostrophes pour les banaliser.

    > ⚠️ On utilise une double redirection en sortie `>>` car il faut concaténer les
    > différentes opérations d'écriture dans le fichier résultat.
    </details>

4. Étant donné un fichier [`listCles.txt`](./listeCles.txt), qui contient une
    clé (une partie d'un DOI) par ligne.  
    Étant donné un fichier de données [`listeDOI.txt.gz`](./listeDOI.txt.gz) qui
    contient des mini-notices avec leur DOI.  
    Écrivez un script shell qui utilise le fichier de clés de sélection avec
    `grep` sur le fichier de DOI, pour récupérer chaque sélection dans un fichier
    résultat différent.  
    Les noms de ces fichiers résultats contiendront la valeur de la clé de sélection.

    > 💡 Dans cet exercice, on utilisera:
    >
    > - `while`
    > - la redirection (possible après `done < listeCles.txt`)
    > - `zcat` (pour éviter de décompresser le fichier de DOI)
    > - `grep` pour sélectionner les notices

    <details>
    <summary>Voir la solution</summary>

    ```bash
    #!/usr/bin/env bash

    while read KEY
    do
        NAME=selection_$KEY
        zcat listeDOI.txt.gz | grep "$KEY" > $NAME.txt
    done < listeCles.txt
    ```

    </details>

    > ⚠️ Il est important de noter que, surtout pour le fichier des critères de
    > sélection, le traitement se déroule sous Unix/Linux. Par conséquent, il faut
    > prendre garde aux fins de ligne qui doivent être de type Unix (`\n`).  
    > La présence de fins de ligne de type Windows (`\r\n`) perturbe les opérations
    > de sélection comme avec `grep` (matching incorrect).