Stage rentrée UNIX - Partie I
2ème année Ecole d'Informatique - Filière RICM


Contenu de la partie 1
Cette partie  présente des rappels sur l'interprête de commandes Unix, concernant la manipulation des fichiers, des utilisateurs, des processus et de l'environnement de travail. La liste des points abordés est plus précisément donnée ci-dessous. Dans cette liste, seuls les utilisateurs ne connaissant pas ou très peu l'environnement Unix liront la section 1. Les autres utilisateurs pourront directement commencer par  la section 2.

  • 1- Opérations de base avec les fichiers
  • 3- Manipulations avancées de fichiers
  • 4- Manipulation de processus
  • 5- Manipulation de l'environnement
  • 6- Ecriture de scripts shell

  •  

     

    Solutions

    1- Opérations de base avec les fichiers - rappels

    1.1 Le répertoire

        Un répertoire (appelé encore catalogue) contient un ensemble de fichiers et/ou de sous-répertoires, un fichier étant composé d'un nom et d'un ensemble de données stockées sur disque. Vu par l'utilisateur, le système de fichiers est donc organisé comme une arborescence dont les noeuds sont des répertoires et les feuilles des fichiers simples.
    A la connexion, un utilisateur se retrouve dans un répertoire qui lui est propre (le home directory) et qui est destiné à contenir les données personnelles de cet utilisateur.

    1.2 Désignation des fichiers et répertoires

        Un fichier ou répertoire est désigné au moyen d'un chemin d'accès, qui indique sa position dans l'arborescence globale qui contient tous les répertoires gérés par le serveur.
        Il existe deux moyens de désigner des objets (fichiers ou répertoires) dans une arborescence: la désignation absolue et la désignation relative.
        La désignation absolue indique le chemin à suivre dans l'arborescence globale (depuis la racine /), pour accéder à l'objet voulu. Par exemple, /a/u1/durand désigne l'objet durand situé dans le répertoire u1 lui-même situé dans le répertoire a sous /.
        La désignation relative précise le chemin à suivre pour accéder à l'objet voulu, à partir du répertoire courant. Par exemple, si vous vous trouvez dans le répertoire /a/u1, le nom durand/programs désigne l'objet programs situé dans le répertoire durand lui-même situé dans le répertoire courant.
        Le nom ../ est un nom générique, qui désigne toujours le répertoire père du répertoire courant. Avec l'exemple précédent, ../ désigne tous les objets situés dans le répertoire /a.
    ../u2 désigne un objet de nom u2 situé dans le répertoire /a.

    1.3 Changement de répertoire courant (cd)

        Au moment de votre connexion, vous vous retrouvez dans votre répertoire de travail (qui est à ce moment votre répertoire courant). Vous pouvez changer de répertoire courant via la commande cd (Change Directory). En tapant cd <nom_rep>, (<nom_rep> étant un nom absolu ou relatif de répertoire), votre répertoire courant devient <nom_rep>.
        La commande cd sans arguments permet de revenir à tout moment à votre répertoire de travail (le home directory).
        La commande cd ~nom d'utilisateur permet d'aller, si les droits le permettent, au répertoire de travail de l'utilisateur donné.
        La commande cd / permet d'aller au sommet de l'arborescence.
        La commande cd .. permet de remonter au répertoire père du répertoire courant. Comme dit précédemment, quelque soit le répertoire courant, la chaîne .. désigne en effet toujours le répertoire père.

    Les commandes pushd et popd permettent également de  se  promener  dans  le
    système de fichiers. La commande pushd <repertoire> est équivalente a cd <repertoire> à la  difference que lorsque  l'on exécute  popd,
    on  revient  au répertoire ou l'on était avant d'appeler pushd. On peut empiler autant de répertoires que l'on veut avec pushd et on les dépile avec popd. Pour voir la liste des répertoires empilés, on utilise la commande dirs.

    1.4 Connaissance du répertoire courant (pwd)

        La commande pwd (print working directory) permet de savoir dans quel répertoire courant on se situe à un instant donné (cette commande affiche le nom absolu du répertoire courant).

    1.5 Copie d'un répertoire (cp -r)

        La commande cp, utilisée avec l'option r, permet de copier rétrécissement le contenu d'un répertoire (c.a.d l'arborescence complète des sous-répertoires et fichiers). Par exemple:
    cp -r <rép1> <rép2>
    crée une copie de <rép1> dans <rép2> si <rép2> existe déjà, sinon cette commande crée une copie de <rép1> appelée <rép2>.
     
    Exercice
    Créez un répertoire temporaire nommé TEMP
    Copiez dans ce répertoire TEMP un répertoire de votre choix

    1.6 Consultation d'un répertoire (ls)

        La commande ls (list directory) permet de lister le contenu d'un répertoire. Cette commande a la possibilité d'être utilisée avec des options qui permettent de la spécialiser.
        De même que pour toutes les commandes qui acceptent des listes de noms en paramètre, on peut utiliser des caractères spéciaux pour faciliter l'écriture de la commande.

    1.7 Les caractères spéciaux

        Pour manipuler un objet qui possède un caractère spécial dans son nom, il faut indiquer explicitement à l'interprète de ne pas prendre en compte le caractère spécial en faisant précéder ce caractère de \. Par exemple, pour lister un fichier de nom fic*, il faut taper ls fic\*.
    En utilisant les caractères spéciaux, l'utilisateur définit des patrons, des modèles d'expressions que l'on appelle des expressions régulières.
    Exercice
    a. Essayez la commande ls avec les options -a, -l et -R. 
    b. Utilisez également les options de factorisation d'écriture de ls : faites afficher tous les fichiers dont le nom se termine par .c.Trouvez deux méthodes permettant d'afficher le nom de tous les fichiers dont le nom commence par un h ou un s. Faites afficher tous les fichiers dont le nom contient exactement 5 caractères. 
    c. Allez dans le répertoire racine. Vous devez voir le sous-répertoire bin qui contient les binaires (programmes) correspondant a la majorité des commandes Unix. La commande ls bin/etc donne la liste des fichiers de configuration du système. 

    1.8 Complétion

        Il s'agit d'un moyen qu'offre l'interprète de commandes pour compléter automatiquement les noms de fichiers intervenants dans une commande shell. On dispose de 2 caractères qui dans des situations de complétion ont les significations suivantes :
    Escape Escape : donne la liste des noms pouvant satisfaire la contrainte,
    Tab : tente une complétion.
    Par exemple, si l'on tape more ~durand/sean suivi de tab, l'interprète remplace cette commande par more suivi de l'ensemble des noms de fichiers ou de répertoires qui se trouvent sous le répertoire ~durand et dont le nom commence par sean.

    1.9 Création de répertoire (mkdir)

        Pour créer un répertoire de nom <nomrep>, il faut utiliser la commande mkdir <nomrep>. Le répertoire créé permettra de stocker des fichiers ou des sous-répertoires, de la même façon que votre répertoire racine.

    1.10 Copie de fichiers (cp)

        La commande cp permet de copier le contenu d'un fichier dans un autre. Par exemple ; cp <f1> <f2> copie le contenu de <f1> dans le fichier de nom <f2>. Si <f2> n'existe pas déjà, il est automatiquement créé.

    1.11 Renommage d'un fichier (mv)

        La commande mv permet de changer le nom d'un fichier. Par exemple, mv <f1> <f2> renomme <f1> en <f2>. Il n'existe alors plus de fichier de nom <f1>.

    1.12 Consultation du contenu d'un fichier (more, less, cat)

        Pour visualiser le contenu d'un fichier qui contient du texte, il existe la commande cat. Cette commande est utilisée en fournissant en paramètre le(s) nom(s) du ou des fichiers que l'on souhaite visualiser.
        Pour visualiser plus facilement les fichiers de grande taille, il existe une autre commande appelée more. Cette commande affiche le fichier page par page, une page correspondant à la quantité de données visualisable dans la fenêtre courante.
        La commande less dans son utilisation la plus simple est identique à more. Cependant c'est une commande qui propose de nombreuses manipulations avancées (recherches, défilement en avant, en arrière, etc.) en utilisant la logique et la syntaxe de vi.

    1.13 Destruction d'un fichier

        rm permet de détruire des fichiers. Attention, le système Unix ne permet aucune récupération des fichiers supprimés.
        On peut détruire des répertoires par rmdir (remove directory). Cette commande implique que les répertoires à détruire soient vides (attention aux fichiers cachés dont le nom commence par un point).
     

    2. Les manuels en ligne

    Il est possible, par la commande man, d'obtenir des informations sur le fonctionnement d'une commande (en particulier, sur les options disponibles). Pour ceci, il faut taper man numéro-du-manuel nom-de-la-commande. Le numéro du manuel est optionnel. La commande particulière man intro donne la liste des commandes disponibles. Les manuels sont organisés de la manière suivante :

    "man intro" donne la liste des commandes disponibles documentées.


    Il faut également savoir qu'il existe une version graphique et conviviale du manuel en ligne, accessible par la commande xman.

    3. Manipulations avancées

    3.1 Recherche par rapport au contenu d'un fichier (grep)

        La commande grep permet de rechercher une chaîne de caractères dans un ou plusieurs fichiers. Plus précisément, étant donné une chaîne de caractères et un ensemble de noms de fichiers, grep va rechercher quels fichiers contiennent cette chaîne. Par exemple :
    grep f1( *.c
    recherche quels sont les fichiers suffixés par .c qui contiennent la chaîne f1(
    Exercice
    a. Testez la commande grep sur quelques exemples. Cette commande sera par la suite très utile pour le développement de programmes. 
    b. Le fichier /etc/passwd contient la base de donnée des utilisateurs du système. Donnez la commande affichant la ligne du fichier /etc/passwd vous concernant.

    3.2 Recherche d'un fichier (find)

        La commande find a pour but la recherche de fichiers dans une arborescence du système de fichiers, et éventuellement l'exécution d'une commande sur chacun des fichiers trouvés.
        La commande find <noms_de_fichiers> <expression> parcourt récursivement l'arborescence de fichiers définie par les répertoires ou fichiers fournis en paramètre, en évaluant l'expression booléenne formée à partir des opérateurs donnés ci-dessous pour chaque fichier.
    Exemples:
    find . -type d affiche la liste des répertoires se trouvant sous le répertoire courant.
    find / -name passwd affiche tous les fichiers de nom passwd se trouvant directement ou indirectement sous /.
    find . -type d -exec ls -l {}  \; permet de lister récursivement tous les répertoires et leur contenu à partir du répertoire courant.
    Exercice
    Trouvez la commande permettant de rechercher récursivement tous les fichiers d'un nom donné dans le répertoire courant et dans tous ses sous-répertoire. 
    Que fait la commande find . -name "*~" -exec rm {} \; ?

    3.3 Tri de fichier

        L'opération de tri d'un fichier est fournie par la commande sort. Cette commande tri le contenu du fichier selon une ou plusieurs clés, identifiées par leur positions dans les lignes du fichier. Par exemple, sort +3 <nom_fichier>, va effectuer un tri portant sur le 3ème mot de chaque ligne du fichier <nom_fichier>. La comparaison des mots s'appuie sur le codage ASCII des caractères, qui est conforme à l'ordre lexicographique. Par défaut, le caractère considéré comme séparateur entre mots est l'espace ou la tabulation. Si l'on souhaite utiliser d'autres caractères, alors il faut les spécifier avec l'option -t de la commande sort.
    Par exemple, sort -t ';' +3 <nom_fichier>, effectue le même tri en considérant le ; comme le caractère séparateur entre mots.
    Exercice
    Trier le fichier /etc/passwd selon les noms d'utilisateurs.

    3.4 Substitutions dans un fichier

    La commande sed permet d'effectuer des substitutions dans des fichiers textes. La syntaxe élémentaire de cette commande est la suivante : sed -e <commande de substitution> <nom de fichier>
    La commande de substitution respecte la syntaxe des commandes de l'éditeur vi. Par exemple :
    sed -e s/toto/titi/  f                  remplace dans chaque ligne du fichier f la première occurence de toto par titi
    sed -e s/toto/titi/g  f                remplace dans chaque ligne du fichier f toutes les occurences de toto par titi
    sed -e d/toto/   f                     supprime dans chaque ligne du fichier f la première occurence de toto
    Exercice
    Tester la commande sed sur des fichiers temporaires.

    3.5 Comparaison de fichiers

        La commande diff <f1> <f2> imprime les lignes qui diffèrent entre deux fichiers <f1> et <f2>.

    3.6 Droits associés aux fichiers et répertoires

        Tout utilisateur est repéré dans le système Unix par un identificateur unique appelé user-id (uid). Dans Unix, les utilisateurs appartiennent également à des groupes, identifiés par d'autres identificateurs uniques (group-id ou gid). La commande id permet d'obtenir l'uid et le gid de l'utilisateur courant.

    Les fichiers et répertoires sont associés à des droits de manipulation qui dépendent de l'utilisateur courant. Le système Unix permet de restreindre les droits d'accès à un fichier ou répertoire en fonction du groupe de l'utilisateur courant, si celui-ci n'est pas le propriétaire du fichier ou répertoire. Plus précisément, considérons la ligne suivante, obtenue avec la commande ls -l :

    -rwxr-xr-- 1 durand staff 12543 Sep 24 17:54 TD1
     

    Les différentes informations sont découpées dans le tableau suivant:

    type
    user
    rights
    group
    rights
    others
    rights
     
    owner
    group
    size
    last modification
    name
    -
    rwx
    r-x
    r--
    1
    durant
    staff
    12543
    Sep 24 17 :54
    TD1
    qui montre les points suivants:
        Pour changer les droits d'accès à un fichier ou à un répertoire, on utilise la commande chmod (change mode) de la manière suivante. Les trois niveaux (user, group et others) sont désignés par u, g et o. Par exemple, chmod u=rw TD1 change le droit de l'utilisateur en lecture/écriture. De même, chmod g+w ajoute le droit d'écriture aux membres du groupe. Chmod g-w effectue l'opération inverse.
    On peut également utiliser le codage octal (utile pour exprimer une valeur sur 3 bits). Par exemple, chmod 754 TD1 effectue les opérations suivantes :
        Pour changer le groupe auquel appartient un fichier, il faut utiliser la commande chgrp <nom-du-nouveau-groupe> <nom-du-fichier>. De même, pour changer le propriétaire d'un fichier, il faut utiliser la commande chown <nom-du-nouveau-propriétaire> <nom-du-fichier>.
    Exercice
    a. Changez les droits d'accès et propriétaires de quelques fichiers et répertoires. 
    b. Analysez la session suivante : 
    $ ls -l 
    $ -rw-r-r--1 genthial interv 147 oct 10 16 :55 essai 
    $ essai 
    $ sh : essai : cannot execute 
    c. Quelle est la cause du message d'erreur ? Que faut-il faire pour remédier à cette erreur ?

    3.7 Archivage et compression de répertoires et fichiers

        L'archivage et la compression de répertoires et fichiers peuvent être requis pour effectuer des sauvegardes de données, ou bien pour transférer des données sur le réseau, par exemple d'un utilisateur à un autre.
        La commande tar permet de produire une archive à partir d'un répertoire donné :
    tar cvf <nom_archive> <nom_répertoire>
        L'archive créée contient toutes les données se trouvant sous <nom_répertoire>, et mémorise l'organisation en fichiers de ces données. La commande qui permet de reproduire cette organisation a partir de l'archive produite est la suivante :
    tar xvf <nom_archive> <nom_répertoire>
        La compression est un mécanisme qui permet de réduire la taille mémoire occupée par des données en leur appliquant un algorithme de compression.
        La commande gzip effectue de la compression.
    gzip <nom_fichier> produit le fichier compressé de nom <nom_fichier>.gz
    gunzip <nom_fichier>.gz reproduit le fichier <nom_fichier>

     
    Exercice
    a. Créez une archive compressée d'un de vos répertoires (appelez la TEST.tar.gz). 
    b. Créez un nouveau répertoire temporaire (ESSAI) 
    c. Copiez TEST.tar.gz dans ESSAI 
    d. Allez dans ESSAI et reproduisez le répertoire TEST à partir de son archive. 
    e . Par mail, envoyez a vous-même ou a un autre binôme l'archive compressée TEST.tar.gz, au moyen d'un attachement de fichier. Vérifiez en décompressant et "désarchivant" que les données reçues sont correctes.
     

    3.8 Liens

    Il est possible d'associer plusieurs noms à un même fichier par un lien physique. La commande "ln" permet de créer un lien c'est-à-dire d'ajouter
    un nom à un fichier. La modification de l'un (du fichier ou du lien) entraine la modification de l'autre.
    Par exemple sous le repertoire /users/student/INFO2/duchemol :
    ls -l f1 donne : -rw-rw-r--  1 duchemol staff    0 Sep 24 18:04 f1
    ln f1 f2 suivi de ls -l f1 donne : -rw-rw-r--  2 duchemol staff    0 Sep 24 18:04 f1
    et ls -l f2 donne : -rw-rw-r--  2 duchemol staff    0 Sep 24 18:04 f2
    La commande "rm" détruit seulement le nom associé au fichier. Le  fichier lui-meme est détruit en meme temps que son dernier lien. Lorsque f1 est détruit, le contenu de f2 reste inchangé. Si f1 est recréé, le contenu de f2 sera different de celui de f1.
    Les liens physiques ne s'appliquent qu'à des fichiers présents sur le même disque.
    Le lien symbolique (ln -s) permet d'établir des liens entre des fichiers apprtenant à des disques distants. Il faut considérer un lien symbolique comme un raccourci d'écriture d'un nom absolu.
    Exemple :
    ln -s f3 f4 suivi de ls -l f3 donne : -rw-rw-r--  3 duchemol staff    0 Sep 24 18:04 f3
    et ls -l f4 donne : l-rw-rw-r--  3 duchemol staff    0 Sep 24 18:04 f4 -> /users/student/INFO2/duchemol/f3
    Lorsque f3 est détruit, il n'y a plus de contenu associé au lien symbolique f4. Si f3 est recrée, f4 permettra d'en accéder le contenu à nouveau.

    3.9 Les systèmes de fichiers UFS, AFS, NFS

    Le système de fichiers est une partie du système d'exploitation qui s'occupe de la gestion et de la localisation réelle des fichiers. En particulier, le SGF gère la correspondance entre les noms des fichiers et leur localisation, le système de nommage, etc.
    Avec UNIX on utilise principalement trois systèmes de fichiers: UFS (Unix File System) qui est le système gérant les fichiers locaux, AFS (Andrews File System) et NFS (Network File System) qui gèrent l'accès à des fichiers à distance (normalement les administrateurs système choisissent entre AFS et NFS et il n'y en a qu'un qui est présent).
    UFS est le système que vous utilisez tout le temps. C'est lui qui définit la gestion des droits en groupes (g), utilisateurs (u) et autres (o) et les types de droits r,w,x.
    NFS est un système de fichiers distribué (ca veut dire qu'il "tourne" sur plusieurs machines, un réseau, et une machine A peut accéder aux fichiers de la machine B comme si ces fichiers étaient locaux). La gestion des droits dans NFS est celle de UFS, on retrouve le même découpage et les mêmes types de droits.
    AFS est également un système de fichiers distribué qui se différencie de NFS dans le gestion des droits. On dispose de 7 types de droits : Consultation, Lecture, Ecriture, Insertion, Suppression, Administration, Verrouillage.
     
    Les systèmes de fichiers décident du découpage de l'espace disque et souvent les utilisateurs ont droit à un espace limité. Pour vérifier si c'est le cas et si oui, quelle partie de cet espace est utilisée, il existe la commande quota (quota -v donne des informations plus complètes).
     
    Un système de fichiers gère donc un ensemble de fichiers. Il est possible de relier les fichiers gérés par un autre système de fichiers de façon à ce que ses fichiers soient accessibles. La commande appropriée est mount, qui 'est normalement une commande réservée aux administrateurs. Cependant pour visualiser les différents montages dans votre systèmes vous pouvez taper la commande sans paramètres.
    Pour connaître le système de fichier utilisé: dans /etc/default/fs la ligne LOCAL=fstype (comme par exemple LOCAL = ufs) indique le système local, /etc/dfs/fstypes (exemple NFS) indique le système utilisé pour les fichiers à distance.

    4. Notion de processus

    Un processus est un programme qui est en cours d'exécution. A un instant donné, plusieurs processus peuvent s'exécuter sur un même ordinateur. Les processus interviennent non seulement lors de l'exécution des programmes utilisateur (vos programmes écrits en C, Pascal, Fortran, etc.) mais également à la prise en charge (l'interprétation) des commandes que l'utilisateur tape à l'écran.

    4.1 Identification d'un processus (ps)

    Chaque processus est identifié par un numéro unique dans le système (pid, pour process identificator) et c'est au travers de cette identification qu'un utilisateur pourra agir sur le processus (l'arrêter, le redémarrer, etc).
    La commande ps (process status) permet de connaître les identifications des processus actifs (c.a.d en cours d'exécution) à l'instant courant. Il existe un grand nombre d'options associées à cette commande. Par exemple,
    ps liste les processus reliés au terminal1 donné, liste le pid du processus, l'identification du terminal, le temps total d'exécution et le nom du processus
        ps -u nom-d'utilisateur             liste les processus s'exécutant pour un utilisateur donné
        ps -ef                                               affiche de manière détaillée la liste de tous les processus actifs du système.
    Voici un exemple de résultat de l'exécution de la commande ps
    PID TT S TIME COMMAND
    2973 pts/1 S 0:01 -tcsh
    3058 pts/1 S 0:02 xemacs
    Nous voyons qu'il y a deux processus actifs: tcsh (dont on verra un peu plus loin à quoi il correspond) et le programme xemacs. Les identificateurs des processus sont respectivement 2973 et 3058. Les deux processus sont lancés depuis le terminal pts/1 et les temps totaux d'exécution sont donnés dans la colonne TIME.

    4.2 Tâches de fond

    Quand vous lancez un programme, vous perdez la main (vous ne pouvez plus écrire sur l'écran) jusqu'à la fin de l'exécution du programme. Vous pouvez vous dégager d'une exécution en demandant que celle-ci soit transformée en tâche de fond. Pour cela, il faut faire suivre l'appel du programme par le symbole & (option background).
    Si vous avez déjà lancé un programme sans cette option et que vous souhaitez le faire passer en tâche de fond, vous devez interrompre votre programme avec Ctrl-z, puis taper bg. Par la suite, la commande fg (pour foreground) permettra de faire revenir votre programme en tâche normale, si vous le souhaitez, en tapant fg numéro-de-job, le numéro de job étant récupérable au travers de la commande jobs.
    Exercice
    a.Lancez le programme axe 
    b.Arretez ce programme pour le faire passer en tâche de fond 
    c.Faites revenir ce programme en tâche normale

    4.3 Ctrl-c et kill

    Pour tuer un processus en cours d'exécution, il existe deux moyens. Le premier consiste à utiliser la commande kill suivie de l'option -9 puis de l'identification du processus à tuer. L'autre moyen, si vous processus n'est pas une tâche de fond, consiste à taper Ctrl-c dans la fenêtre dans laquelle il a été lancé.

    4.4 Redirection des entrées/sorties d'un programme

    Les entrées/sorties standard
    Sous Unix, la plupart des programmes peuvent être considérés comme des transformations qui travaillent sur les données fournies en entrée et produisent un résultat délivré en sortie ainsi que des éventuels messages d'erreur.
    L'entrée standard de tout programme, ou de toute commande UNIX, est le clavier.
    La sortie standard de tout programme, ou de toute commande UNIX, est l'écran.
    La sortie standard pour les erreurs survenant lors de l'exécution d'un programme ou d'une commande UNIX est aussi l'écran.
     
    Redirection des sorties d'un programme dans un fichier
    Il existe un mécanisme qui permet de rediriger les sorties d'un programme dans un fichier. Pour cela, il faut faire suivre l'appel du programme par le symbole > suivi du nom de fichier voulu:
    nom_prog > nom_fichier.
    Cette possibilité est intéressante lorsque le nombre d'affichage est important, et que l'on souhaite pouvoir vérifier la bonne exécution du programme en étudiant ses traces d'exécution. En utilisant >> au lieu de >, alors la sortie d'un programme est ajoutée à la fin du fichier donné. Attention, avec la commande de redirection >, il est possible d'écraser accidentellement des fichiers (si les fichiers vers lesquels on dirige la sortie existent déjà et contiennent d'autres informations). Il existe des moyens pour éviter cela que l'on va considérer en parlant des shells dans la suite.
    Redirection des entrées d'un programme depuis un fichier
    Il est également possible de rediriger les entrées d'un programme, pour que celui-ci lise les données non pas au clavier mais depuis un fichier donné. Pour cela, il faut faire suivre l'appel du programme par le symbole < suivi du nom de fichier d'entrée.

     
    Exercice
    a. Redirigez les sorties de la commande ls dans un fichier ls_res. 
    b. Recommencez en ajoutant la sortie de la commande ls au fichier ls_res. 
    c. Que fait la commande suivante : cat ls_res > f
    4.5 La communication par tube (pipe en anglais)
    Il est possible de rediriger les sorties d'un programme de telle sorte que les données produites en sortie soient fournies en entrée à un deuxième programme, activé à la suite du premier programme. Le symbole utilisé est le | (le tube ou le pipe en anglais).
    Pgm1 | Pgm2 exécute Pgm1, et redirige les sorties de Pgm1 en entrée de Pgm2.

     
    Exercice
    Que fait la commande suivante: ls-l | wc -l (utilisez man pour comprendre ce que fait wc).
    4.6 Séquencement
    L'opérateur de séquencement est le point virgule. Il permet d'exécuter plusieurs commandes en séquence.
    Cde1 ; Cde2 ; Cde3 engendre l'exécution de Cde1, puis de Cde2, puis de Cde3.

     
    Exercice
    Construire la commande composée de trois sous-commandes séquentielles, qui effectue l'équivalent de la commande donnée à l'exercice précédent en passant par un fichier intermédiaire : 
    1.le résultat de ls -l est placé dans un fichier f 
    2.on comptabilise le nombre de lignes de f 
    3.on détruit f

    5. Un processus particulier, l'interprète de commandes (shell)

    5.1 Notion de shell

    Le  shell  est  un  interprêteur  de  commandes.  Il   permet à l'utilisateur  d'exécuter  toutes  les  commandes offertes par le système. Son rôle est  de  préparer  l'exécution d'un  programme, en  substituant les expressions régulières dans la commande et en préparant les arguments qui seront passés  au  programme  à  exécuter.
    Historiquement, le premier shell disponible sur les systemes Unix est  "sh"  appele'  aussi  le "bourne shell". C'est un shell très simple qui a l'avantage d'être  disponible  sur  toutes  les  plateformes Unix. Par la suite, ont été developpés plusieurs shells étendant sh, tel que le  C  shell (csh  et  tcsh),  le  Korn shell (ksh) et le Bourne-Again shell (bash).  Même si ces différents shells sont assez proches, il existe des différences entre les ensembles des commandes interprétées et les syntaxes utilisées. Pour changer de shell (par exemple parce que le shell courant est différent de celui que l'on connaît le plus), il suffit de taper la commande de lancement du shell voulu: csh, tcsh, sh, etc.

    Lors de la connexion d'un utilisateur, des fichiers de configuration bien précis sont considérés :

    (pour bash, sh et ksh) /etc/profile puis .profile
    (pour csh)  /etc/login puis .login
    Les fichiers sous /etc décrivent une configuration valable pour tous les utilisteurs. Chaque utilisateur peut surcharger ou compléter cette configuration. Pour savoir quel est le shell affecté par défaut à un utilisateur, une possibilité consiste à consulter le fichier /etc/passwd.

    5.2 Manipulation des utilisateurs au travers du shell (who, id, passwd)

    Tout utilisateur est repéré dans le système Unix par un identificateur unique appelé user-id (uid). Dans Unix, les utilisateurs appartiennent également à des groupes, identifiés par d'autres identificateurs uniques (group-id ou gid).
    La commande who permet de connaître la liste des utilisateurs connectés au système à l'instant courant.
    La commande id permet d'obtenir l'uid et le gid de l'utilisateur courant.
    La commande passwd permet de changer le mot de passe Unix de l'utilisateur courant. Pour cela, il suffit de taper à la suite du prompt la commande passwd, et de suivre les instructions qui vous sont fournies.
    Voici des exemples d'exécution de ces commandes:
    boyer dtremote Oct 15 09:11 (uauka.inrialpes.)
    rippert pts/5 Jan 10 07:46 (timor:0.0)
    rousset pts/10 Jan 03 09:25 (butung.inrialpes)
    boyer pts/17 Oct 18 16:56 (uauka:0.0)
    boyer pts/19 Oct 19 12:25 (uauka:0.0)
    charra pts/20 Jan 04 10:12 (cato:0.0)
    rousset dtremote Jan 03 09:25 (butung.inrialpes)
     
    La commande donne la liste des utilisateurs en spécifiant également depuis quand ils sont connectés et depuis où (terminal et machine). Nous remarquons qu'un utilisateur peut figurer plusieurs fois ce qui veut dire qu'il est en train d'exécuter plusieurs shells (la manière la plus simple pour y arriver et d'ouvrir plusieurs fenêtres).
    uid=50648(vmarango) gid=50056(sirac) groups=1(staff)

    5.3 La complétion automatique

    La complétion automatique est une facilité du shell qui permet à l'utilisateur de ne pas écrire en entier le nom d'une commande ou d'un fichier/répertoire. Pour utiliser la complétion automatique suffit de commencer le nom dont il s'agit et de taper TAB. Le shell propose alors une liste de possibilités. Suivant le contexte le shell propose soit des noms de commandes, soit des noms de fichiers.
    Voici quelques exemples de fonctionnement de la complétion automatique:
    hoff > more f[TAB]
    le shell reconnaît qu'il s'agit d'un fichier/répertoire et propose

    f     f.txt     fmdictionary     fminit/

    hoff > more f

    hoff > f[TAB]
    le shell reconnaît qu'il peut aussi s'agir d'une commande et propose

    f         fformat     foreach     fun

    factor    fg          fjust       formail
    ...
    La complétion automatique peut ne pas être activée automatiquement au lancement du shell. Pour cette activation une configuration particulière est nécessaire et on va en discuter dans la partie Configuration de l'environnement.

    6.4 Configuration du shell

    Nous avons dit que le premier processus lancé à la connexion d'un utilisateur est l'interpréteur de commandes. Le shell effectue une configuration préalable qui est spécifiée. Les fichiers de configuration manipulent:

    Aliasing

    Certaines commandes peuvent être longues à taper ; Le mécanisme d'aliasing permet de dire à l'interprête de commandes : considère que tel mot signifie telle commande. Par exemple :
    (en csh) alias ll ls -l  (ll sera automatiquement associé à ls -l)
    (en bash) alias ll='ls -l'
    Pour supprimer un alias: unalias <nom d'alias>

    Les variables

    Les variables manipulés par le shell se divisent en deux : les variables d'environnement et les variables propres au shell. Les variables d'environnement sont manipulées et utilisées par les différents programmes du système. Par exemple la variable d'environnement $DISPLAY est utilisée par les programmes  X (programmes graphiques)  pour connaitre   l'addresse  du  terminal  sur  laquelle  la  fenêtre correspondant à l'application doit s'afficher. La variable  $LPDEST  est utiliseée par le spooler d'impression "lpr" ou "lp".
    Les variables d'environnement sont accessibles par les programmes lancés par le shell, alors que les variables du shell sont propres au shell et ne sont pas héritées par ces programmes. Par convention, les variables du shell sont en minuscules et  les variables d'environnement sont en majuscules.
    Certaines variables d'environnement sont  initialisées directement à partir des variables correspondantes du shell. Par exemple $PATH est initialisée à partir de la variable shell $path.

    Les variables d'environnement

    Par convention les variables d'environnement s'écrivent en majuscules et dans la plupart des cas elles ne sont positionnées qu'une fois, au début de la session. Pour positionner la valeur d'une variable d'environnement il faut utiliser la commande setenv da la manière suivante (pour annuler une affectation, il existe la commande unsetenv) :
    setenv <NOM_DE_VARIABLE> <valeur>
    Par exemple : setenv DISPLAY samoa:0

    On peut aussi cumuler des valeurs dans une variable(ex: setenv PATH {$PATH}:/usr/local/bin).

     
    Pour visualiser une variable d'environnement il faut utiliser la commande echo comme ceci:
    echo $<NOM_DE_VARIABLE>.
     

    Principales variables d'environnement

    Il est important de mentionner que rien n'oblige à définir les variables d'environnement (sauf celles qui de toute façon sont définies automatiquement). Pour cette raison il est possible d'avoir :
    hoff> echo $LIBRARY_PATH
    LIBRARY_PATH : Undefined Variable
     
    Exercice
    Les valeurs de l'ensemble des variables d'environnement sont données par la commande env. Testez cette commande.

    Les variables du shell

    Par convention les variables de shell sont écrites en minuscules. Elles peuvent être modifiées pendant la session et différer d'un shell à un autre.
    Pour positionner une variable de shell la syntaxe est la suivante (l'opération inverse est faite par unset) :
     
    set <variable> = <valeur>
    comme dans
    set path = /u1/boole/bin:~diard/bin/
    La visualisation des valeurs est faite également en utilisant la commande echo comme dans
    echo $path.

    Principales variables de shell

    Voici la liste des variables le plus couramment utilisées.
    Exemple: le résultat de set prompt = "%n@%m [\!] ~>" est diard@boole [1] ~> si l'utilisateur s'appelle diard et est connecté sur boole.
    La commande set affiche la liste de toutes les variables du shell.
    5.5 Utilisation des quotes
    Pour toute chaîne manipulée dans une commande, il faut faire attention à l'utilisation (éventuelle) des quotes. Il y a trois types de quotes qui sont interpretés différemment.
                           echo 'ls -l $FILE'  produit:  ls -l $FILE
                          echo "ls -l $FILE" produit : ls -l fichier.c
  • Les antiquotes (backquotes) `` permettent de faire de la substitution suivie par l'exécution du résultat de la substitution. Par exemple,  echo `ls -l $FILE` produit -rw-r--r--   1 duchemol   system     11338 Sep 29 16:09 fichier.c
  •  
    Exercice
    Testez les commandes suivantes.
         echo "Mon nom d'utilisateur est : `whoami`." 
         echo "Mon \"HOME\" est : " $HOME "."

    5.6 Les différents fichiers de configuration

    Dans cette section nous allons parler des différents fichiers de configuration en expliquant leur rôle et en donnant des exemples de fichiers typiques.

    Le fichier .login (tcsh) ou .profile (bash)

    Le fichier .login est utilisé pour positionner les variables d'environnement et pour mettre à jour des propriétés valables pendant toute la session. Il est interprété une seule fois par le shell au début de la connexion.
    ###########################################################
    # Example .login file #
    ###########################################################
    #variables d'environnement
    setenv TERM xterm
    setenv EDITOR /usr/ucb/vi
    setenv PRINTER hp
    setenv DISPLAY "boole:0.0"
    unset autologout
    umask 002
    Il existe un .login qui est commun à tous les utilisateurs (dans /etc) et qui peut fixer des propriétés et faciliter la configuration effectuée par l'utilisateur.

    Le fichier .logout

    Le fichier .logout spécifie les actions à effectuer lors de la déconnexion d'un utilisateur.

    Les fichiers de configuration additionnels (.cshrc, .bashrc, etc)

    Selon les shells utilisés, différents fichiers de configuration additionnels peuvent être définis. Par exemple, le fichier .cshrc est utilisé pour positionner les variables du shell csh, à chaque session. Ces fichiers peuvent compléter ou surcharger la configuration définie par les fichiers de configuration plus généraux (.login par exemple). Ils peuvent également contenir des commandes spécifiques au shell utilisé.
     

    Un exemple de fichier .cshrc
     

    ###########################################################
    # Example .cshrc file #
    ###########################################################
    # Set path shell variable
    set path = ( /usr/bin /usr/local /usr/local/bin
    /usr/bin/X11 /usr/ucb /usr/opt/bin ~ )
    # Don't overwrite existing files with the redirection character ">"
    set noclobber
    # Don't create core dump files when a program blows up.
    limit coredumpsize 0
    # Remember my 40 most recent events
    set history=40
    # Save the most recent 40 events when I log out
    set savehist=40
    # Substitute the filename to be completed when I type an
    # <ESC> at the command line
    set filec
    # Tells the shell to ignore .o files when trying to
    # complete filenames when filec is set. (This doesn't
    # hold if the .o file is the only on that could be completed.
    set fignore=.o
    # Tells "filec" not to cry if it can't complete a file.
    set nobeep
    # Notify me when the status of background jobs change
    set notify
    # Don't let me log out by pressing <ctrl-d>
    set ignoreeof
    # Set prompt to have the following form: user@host[event]~>:
    set prompt="%n@%m%u [%h]~>"
    # Shortcut aliases
    alias c 'clear'
    alias ll 'ls -la'
    # end of .cshrc file

    Le fichier .history

    Le fichier .history garde l'historique des commandes lancées par l'utilisateur. Ce fichier est également mis à jour lors d'une déconnexion et l'utilisateur peut utiliser ces dernières commandes à la connexion suivante. Le fichier peut être visualisé comme tout autre fichier texte.
    La commande qui peut donner la liste des dernières commandes exécutées est history.
    !! permet de ré-exécuter la dernière commande, et !<n> permet de ré-exécuter la commande numérotée <n>.
    > history
    1 16:52 source .cshrc
    ...
    10 17:36 more .logout
    11 17:36 vi .logout
    12 17:36 exit
    ...
    15 17:37 ls
    ...
    21 9:52 maker
    22 9:58 more .history
    ...
    35 10:08 history > history_ex.txt
     
    Exercice
    Pour vous promener dans l'historique et réutiliser des commandes, vous pouvez utiliser Ctrl-P (aller en arrière dans la liste, P de previous) ou Ctrl-N (aller en avant, N de next). A la place de Ctrl-P/Ctrl-N il est possible d'utiliser les flèches. 
    Pour ré-éxecuter directement à une commande dans la liste donnée par la commande history, tapez !<numéro de commande>
    Le fichier .xhost
    Le fichier .xhost est utilisé pour donner des droits d'affichage à d'autres machines. Le x vient de XWindows (le système d'affichage graphique de UNIX). Vous vous êtes certainement déjà retrouvés dans la situation où en essayant de lancer une application vous recevez le message:
    Xlib: connection to "samoa.inrialpes.fr:0.0" refused by server
    Xlib: Client is not authorized to connect to Server
    /usr/local/bin/xterm Xt error: Can't open display: samoa.inrialpes.fr:0
     
    Ceci vient du fait que vous avez pas donné le droit d'affichage (sur votre machine) au serveur qui exécute l'application. Pour faire ceci, dans le fichier .xhost il faut mettre le nom du serveur. Ainsi si votre .xhost a la forme suivante, alors les machines boole et hoff sont autorisées à afficher sur votre machine.
    boole.imag.fr
    hoff.imag.fr
     
    Vous pouvez vous passer du fichier .xhost en utilisant la commande xhost au niveau du shell ou bien dans l'un de vos fichiers de configuration. Les formes d'utilisation sont les suivantes:
     
    Exercice
    Lancez une application graphique (axe par exemple) et faites afficher l'interface sur l'écran d'un binôme voisin.
    Le fichier .rhosts (rlogin, rsh)
    Le fichier .rhosts est utilisé pour indiquer quels utilisateurs ont le droit de se connecter par rlogin ou rsh sur le compte de l'utilisateur courant. Ces personnes auront le droit d'effectuer un rlogin (remote login) sur ce compte (dans certains cas qui dépendent de l'administration système, sans fournir de mot de passe.).
    La commande rlogin est utilisée de la manière suivante:
  • rlogin <nom de machine> : l'utilisateur se connecte sous le même nom de login sur la machine <nom de machine>
  • rlogin <nom de machine> -l <nom d'utilisateur> :    l'utilisateur se connecte sous le nom <nom d'utilisateur>
  • La commande rsh (remote shell) est également utilisable avec le fichier .rhosts. Rsh permet d'exécuter une commande sur une autre machine sans explicitement se connecter et lancer de shell interactif. Pour l'utiliser:
     
    Exercice
    Testez la commande rsh, en lanceant par exemple un xterm sur une machine distante. 
    Que faut-il faire pour que le xterm s'affiche sur votre écran courant ?

    6. Interprêtation des commandes shell

    6.1 Substitution des variables
    Lorsque l'on tape une commande, avant de l'exécuter le shell analyse la  commande. La première étape de cette analyse consiste à voir si la commande tapée contient un alias. Si cela est le cas, l'alias est remplacé par son contenu. La deuxième étape consiste à substituer les variables par leur contenu (une variable est toujours precedée par $).

    Prenons par exemple la commande : ll ${FILE}
    Après la première étape d'analyse, elle devient: ls -l ${FILE}
    Après la deuxième étape d'analyse, si la variable FILE contient la chaîne fichier.c, elle devient: ls -l fichier.c

    On peut interdire au shell de substituer une variable en la  mettant entre quotes. Exemple, si on tape la commande:  ll '$FILE', après la deuxième étape, $FILE n'est pas substitué : ls -l $FILE

    Certaines constructions plus complexes sont disponibles au niveau des variables du shell (définies par set et non par setenv).

    • ${#var} : est substitué par le nombre d'éléments que contient  la variable var. Par exemple,  echo  $#path  nous  donne  le nombre  de  chemin d'accès que contient la variable path.
    • $n : n est un entier. Est substitué par la valeur du <n>ieme argument passé au shell.
    • $0: est substitué par le nom du programme que l'on est en train d'exécuter.
    • $1: est substitué par le premier argument passé au programme que l'on  est  en train d'executer.
    • $* : est substitué par la liste de tous les arguments passés au programme courant.
    • ${?var} : est substitué par 1 si la variable est définie,  par  0 sinon

    • Par exemple, echo {?path} est substitué par 1 puisque $path est définie.
    • $< : est substitué par une ligne de l'entrée standard. Cette notation est utilisée pour lire une chaîne de caractère depuis l'entree standard.
    Exercice
    Que fait le script shell suivant ? Le saisir dans un fichier sh1 et le tester
         #!/bin/tcsh
         echo " Nom du fichier :"
         set nom=$<
         ls -l $nom

    6.2 Substitution de commandes
    La substitution de commandes concerne les chaînes de caractères entre antiquotes (`).  Après avoir substitué les alias et les variables, la troisième étape d'analyse d'une commande est la substitution des chaînes entre  ` par le résultat de leur exécution.

    Prenons par exemple la commande : set files=`ll $home`
    Après le remplacement de l'alias ll par "ls -l", et  de la  variable $home  par  le répertoire initial de l'utilisateur, la chaine "ls -l ~duchemol" est substituée par  son  résultat,  c'est  à  dire par l'ensemble des fichiers présents dans le répertoire ~duchemol.

    Si  le  repertoire   ~duchemol   contient   deux   fichiers,   en l'occurrence  "fichier1.c"  et "fichier2.c", la commande (après la troisieme étape) devient : set files=(fichier1.c fichier2.c)
     

    7. Le langage de programmation (les scripts)

    Comme nous l'avons mentionné dans la section précédente, le shell n'est pas seulement un interprète d'un langage de commandes mais aussi il dispose d'un langage de programmation.

    Certains traitements répétitifs peuvent être automatisés en  regroupant  l'ensemble des commandes nécessaires pour effectuer le traitement  dans un fichier qui sera interpreté par  le  shell en "batch". C'est le mode non interactif du shell et il est possible avec la commande interne "source"
            source shell_script
     

    Tout script qui est programmé pour être exécuté par un shell doit commencer par la ligne suivante qui force l'interprétation de ce fichier par le shell précisé.
    #!/bin/<nom shell>
     
    Dans le reste du script, toute ligne commencant par # est considérée comme un commentaire.
     
    7.1 Utilisation des commandes prédéfinies
    Chaque script peut utiliser les commandes prédéfinies du shell. L'exécution du script ci_après produit à l'écran la chaîne ESSAI.
     
    #Exemple de script
    #!/bin/tcsh
    echo ESSAI
    7.2 Le passage à ligne
    Dans les scripts les retour arrière (RETURN) sont considérés comme des séparateurs. Si une commande est écrite sur plusieurs lignes l'interpréteur ne la comprendra pas. Pour écrire les commandes en entier et sur plusieurs lignes, il faut utiliser le symbole \ qui indique que la ligne qui suit fait partie de ce qui précède.
    #Exemple de script
    #!/bin/tcsh
    setenv PATH /bin/usr \
                /bin/usr/P1 \
                ~diard/bin
     
    7.3 Variables entières
    Par défaut, les variables sont de type chaînes de caractères. Il existe toutefois un moyen de définir des variables entières, pour accélérer certains calculs. Si la variable est numérique, l'affectation est faite comme ceci:
    (en tcsh) @   <variable>=<valeur>
     
    #Exemple de script tcsh
    #!/bin/tcsh
    #affectation à a l'entier 1
    @ a=1
    #affectation à b la chaîne contenant le caractère 1 en tcsh
    set b=1
    7.4 Variables de type liste
    Deux types de variables sont supportés: les variables "simples" et les variables listes.
    Pour les variables listes, $# indique le nombre de composants (séparés par des blancs).
    #Exemple de script tcsh
    #!/bin/tcsh
    #b est une variable simple
    set b=1
    #b_liste est une liste de trois éléments
    set b=(1 2 3)
    echo $#b
    #doit afficher 3
     
    Exercice
    Complétez le script suivant pour qu'il affiche le nombre de fichiers présents dans le répertoire /usr/bin/*.
    (en tcsh)
    set f=(/usr/bin/*)
    ...
     
    7.5 Accès à la valeur d'une variable
    Pour accéder à la valeur d'une variable il faut utiliser le $.
    #Exemple de script tcsh
    #!/bin/tcsh
    #affectation à b la chaîne 1
    set b=1
    #b_liste est une liste de trois éléments
    set b=(1 2 3)
    #affichage de la valeur de a, le résultat est le nombre 1
    echo $a
    #affichage de la valeur de b_liste
    echo $b_liste
    #le résultat est 1 2 3
     
     
    7.6 L'instruction if-then-else :
    La syntaxe générale de cette instruction est la suivante en tcsh:
    if (exp) then
        liste_commandes
    [else if ( exp ) then
        liste_commandes] ...
    [else
        liste_commandes]
    endif

    Il existe une syntaxe abrégée:

    if (exp) commande

    Les expressions conditionnelles sont soit celles que vous connaissez du langage C, soit des expressions portant sur des fichiers comme celles qui suivent ($var est un fichier):

    ATTENTION à la disposition des mots clés et des commandes par rapport à ces mots clés. Dans la première forme de if, le then doit suivre l'expression conditionnelle. Dans la deuxième forme (abrégée) la commande doit également suivre la condition.
     
    #Exemple de script
    #!/bin/tcsh
    #affectation à b la chaîne 123
    set b=123
    if ($b == 123) then
        echo PREMIER_CAS
    else
        echo DEUXIEME_CAS
    endif
    7.7 L'instruction while
    while (exp)
        liste_commandes
    end
    ATTENTION au retour à la ligne après l'expression.
    7.8 L'instruction foreach
    foreach index_var (liste)
        liste_commandes
    end
    Dans les boucles ou les instructions à plusieurs choix on dispose de break qui arrête la boucle et de continue qui arrête l'itération courante de la boucle et commence la prochaine itération.
     
    #Exemple de script tcsh
    #!/bin/tcsh
    #affectation à b la liste 1 2 3
    set b=(1 2 3)
    foreach i ($b)
        if ($i > 1) echo $i
    end
     
    Exercice
    Ecrivez un script shell qui, pour chaque fichier placé dans le répertoire /usr/bin, affiche le nombre de lignes du fichier.
    7.9 Les arguments
    Les arguments passés au script sont récupérables à travers la variable argv (#argv donnant le nombre d'arguments). La n-ième composante d'argv est adressée par $argv[n] ou par $n (ce qui peut donner une erreur si on dépasse la limite).
    L'expression ($*) ou ($argv) permet de récupérer la liste de tous les arguments passés au script. L'instruction shift permet d'enlever le premier élément de cette liste.
     
     
    Exercice
    Ecrivez un script shell qui, pour chaque fichier placé dans un répertoire donné en paramètre, affiche le nombre de lignes du fichier.
     
    7.10 L'instruction switch
    La syntaxe de l'instruction switch est la suivante:
    switch ( para )
        case choix1 :
            liste_commandes
            breaksw
        ...
        default :
            liste_commandes
            breaksw
    endsw
    7.11 L'instruction goto
    L'instruction goto est utilisée de la manière suivante:
    boucle :
    liste_commandes
    goto boucle
     
    Exercice 1
    Ecrivez un script shell qui, pour chaque fichier placé dans votre répertoire courant, effectue les actions suivantes :
       si le nom du fichier satisfait l'expression *.c : le fichier est déplacé dans le répertoire Src
       si le nom du fichier satisfait l'expression *.h : le fichier est déplacé dans le répertoire Inc
       si le nom du fichier satisfait l'expression *.o : le fichier est déplacé dans le répertoire Obj
     
    Exercice 2
    Ecrivez un script qui liste, parmi tous les fichiers situés dans un répertoire donné en paramètre, ceux dont la taille dépasse une taille également donnée en paramètre.

     
    Exercice 3
    Ecrivez un script qui permet de remplacer une chaîne par une autre dans les fichiers indiqués en paramètre.