Aller au contenu

Administration Unix - CM séance 03

4. Commandes et processus

4.1. Généralités sur les commandes Unix

La forme générique d'une ligne de commande dans un shell est :

$ commande [argument]... [redirection]...
  • $ en début de ligne : le prompt

    • signifie que le shell attend une commande
    • il peut être sous la forme : user@machine:répertoire$
    • modifiable par l'utilisateur (vu plus tard)
  • commande : au sens large, elle peut être

    • une commande système (dans /bin ou /usr/bin) : cp, mv, ...
    • une commande administrateur (dans /sbin ou /usr/sbin) : chown, chgrp, ...
    • une fonction builtin du shell : echo, cd, ...
    • une fonction shell définie par l'utilisateur
    • un script (shell, python, etc)
    • n'importe quel fichier exécutable
  • [ ]...

    • les crochets [ ] signifient que c'est optionnel ;
    • ... signifie qu'il peut y en avoir plusieurs
  • [argument]...

    Les arguments sont les informations que l'on passe à la commande.

    Selon la commande, il peut y avoir des arguments optionnels ou obligatoires.
    Par exemple :

    $ cp -f -a fichier destination           # -f -a : optionnels
    

    Les arguments optionnels peuvent avoir une forme longue, plus lisible :

    $ cp --force --archive fichier destination
    

    On peut parfois les regrouper :

    $ cp -fa fichier destination
    

    Dans certaines commandes on peut même suprimer le - :

    $ tar --create --verbose --file archive fichier...
    $ tar -c -v -f archive fichier...
    $ tar -cvf archive fichier
    $ tar cvf archive fichier
    
  • Les redirections (de fichiers) : vues au cours précédent < > >> >| >& ...

Remarque : les tubes | ne font pas partie des redirections de fichiers :

  • les tubes permettent de relier des commandes dans un pipeline :

    $ cmd1 [arg]... [redirection]... | cmd2 [arg]... [redirection]...
    
  • un tube indique aussi la fin d'une commande (comme un ;).

4.2. Environnement du shell

Le shell peut mémoriser des variables :

$ variable=valeur       # affectation, sans espace autour du =
$ echo $variable        # affiche le contenu de variable

Le $ devant variable signifie : "substituer la variable par sa valeur".

Exemple d'usage :

$ f="toto.txt"
$ echo "Copie de $f vers $f.old ..."
Copie de toto.txt vers toto.txt.old ...
$ cp "$f" "$f.old"

Variables de shell :

Le shell fournit automatiquement certaines variables : les "variables de shell" ; certaines ne sont pas modifiables.

Quelques variables de shell

BASH : le chemin d'exécution de ce shell, par exemple /bin/bash

SHLVL : le niveau du shell (premier niveau 1, sous-shell niveau 2, ...)
Créer un sous-shell : $ bash (⟶ SHLVL est incrémenté)
Pour sortir d'un shell : exit

RANDOM : un entier au hasard entre 0 et 32767

Documentation : man bash puis /Shell Variables.

Variables d'environnement :

Certaines variables peuvent conditionner le comportement du shell et de certains programmes : les "variables d'environnement".

Variables d'environnement usuelles

USER : le user courant
Ex : echo $USERthiel
PWD : le chemin courant du shell dans le système de fichier
On peut le manipuler avec la commande cd.
PATH : chemins de recherche des exécutables dans le système de fichier
Ex : /bin:/usr/bin:/usr/local/bin:~/bin
Ordre très important : c'est le premier qui gagne
SHELL : le shell courant
Ex : /bin/bash
DISPLAY : en mode graphique
Adresse de l'écran distant (en local :0)

Pour voir les variables d'environnement : printenv

$ printenv SHELL
/bin/bash
$ printent BIDON            # n'existe pas ⟶ n'affiche rien
$ printenv | more
...                         # toutes les variables

Elles sont souvent en MAJUSCULES pour les distinguer des variables normales.

Fabriquer une variable d'environnement :

$ variable=valeur
$ export variable
ou

$ export variable=valeur
⟶ la variable est marquée "environnement" et sera passée aux sous-shells.

Exemple :

$ A=toto                # variable normale
$ echo $SHLVL $A
1 toto
$ printenv A            # rien car n'est pas une var d'environnement
$ bash                  # création d'un sous-shell
$ echo $SHLVL $A
2                       # le sous-shell ne connaît pas A
$ exit

$ export A              # on l'exporte
$ printenv A
toto                    # c'est bien une var d'environnement
$ echo $SHLVL $A
1 toto
$ bash
$ echo $SHLVL $A
2 toto                  # A a bien été héritée
$ exit

⚠  Mécanisme d'héritage à sens unique :

$ export B=foo
$ bash
$ B=bar                 # B modifiée dans le sous-shell
$ echo $SHLVL $B
2 bar
$ exit
$ echo $SHLVL $B        # nouvelle valeur non obtenue dans le shell
1 foo

Variables d'environnement privées :

On peut lancer une commande en précisant des variables, qui

  • seront pour cette commande des variables d'environnement,
  • et ne seront connues que de la commande.

Syntaxe :

$ [variable=valeur]... commande [argument]... [redirection]...

Exemple :

$ PLIP=plop bash
$ echo $SHLVL $PLIP
2 plop
$ printenv PLIP
plop
$ exit
$ echo $SHLVL $PLIP
1

Usage courant :

$ PATH=... commande arguments

permet de dire au système où chercher cette commande, sans modifier le PATH commun.

4.3. Les commandes sur les processus

Le système tient à jour une table de tous les processus.

🌹  La Commande ps

Affiche la table des processus.

$ ps        # affiche les processus lancés dans le shell courant
$ ps -aux   # tous les processus de tous les utilisateurs

Chaque processus possède :

  • un propriétaire (colonne 1)
  • un PID (Process Identifier, colonne 2) : numéro unique entre 1 et 65535
  • connaît ses temps d'exécution et sa ligne de commande

Chaque processus a un parent = celui qui l'a créé (en général le shell).

Le PID du parent est le PPID (Parent-PID). Pour les afficher :

$ ps -eo user,pid,ppid,command | more

On peut voir les filiations avec pstree :

$ pstree -h     # -h : highlight les parents de la commande courante

À noter : on peut voir le PID du shell courant avec la variable de shell BASHPID :

$ echo $BASHPID

🎩  La commande top

Affiche de manière dynamique et interactive la liste des processus triée.

$ top

Taper ensuite

  • h pour l'aide ; sortie avec Esc
  • pour trier selon MEM : f , aller sur MEM, s , Esc
  • pour afficher/cacher des champs : f, aller sur un champ, Space, Esc
  • q pour quitter

🔔  La commande kill

Envoie un signal Unix à un processus.

$ kill [signal] PID...

Un signal Unix est une sorte de message très court, qu'un processus peut envoyer à un autre processus, et qui peut agir sur lui (l'endormir, le terminer, etc).

Exemple : on lance un programme en arrière plan (symbole &)

$ xclock &
[1] 4977        # [1] = numéro de "job", 4977 = PID du processus xclock
$ kill 4977     # envoie le signal SIGTERM au processus
$
[1]   Complété  xclock      # bash s'est rendu compte que ce job est terminé.

SIGTERM est le SIGnal de TERMinaison ("s'il te plaît, termine-toi"). Le processus recevra le signal et fera en général un exit.

La norme POSIX définit une trentaine de signaux.

Exemple : SIGKILL = le processus est immédiatement tué, sans être averti.

$ xclock &
[1] 5155        # chaque nouveau processus a un PID différent
$ kill -KILL 5155

Chaque signal correspond à un numéro ; voir la liste

$ kill -l
 1) SIGHUP    2) SIGINT     3) SIGQUIT    4) SIGILL     5) SIGTRAP
 6) SIGABRT   7) SIGBUS     8) SIGFPE     9) SIGKILL   10) SIGUSR1
11) SIGSEGV  12) SIGUSR2   13) SIGPIPE   14) SIGALRM   15) SIGTERM
...

On peut utiliser le numéro comme raccourci :

$ kill -9 xxx     # envoi le signal SIGKILL au processus de PID xxx

Le PID spécial -1 signifie "tous les processus" :

$ kill -9 -1      # tue tous les processus qu'on peut tuer
                  # /!\ cela vous délogue brutalement !

Il existe une variante : killall [signal] commande... où on donne le nom de la commande au lieu de son PID :

$ xclock & xclock & xclock &    # on en lance 3 en arrière plan
[1] 5214
[2] 5215
[3] 5216
$ killall xclock                # ils sont tous tués
[1]   Complété              xclock
[2]-  Complété              xclock
[3]+  Complété              xclock

4.4. États des processus

Les processus peuvent être dans 4 états :

  • premier plan : (mode normal)
    le processus occupe l'entrée et la sortie du terminal, jusqu'à ce qu'il ait fini de s'exécuter.
  • arrière plan :
    le processus s'exécute, affiche ses résultats vers la sortie du terminal, mais les frappes dans le terminal ne sont pas envoyées au processus.
    On dit encore que le processus est "détaché du terminal".
  • sommeil :
    le processus ne dispose d'aucun temps CPU, il est interrompu, jusqu'à ce qu'on le réveille.
  • zombie :
    le processus est mort, il ne subsiste plus rien en mémoire, sauf son PID et son code de terminaison (le paramètre de exit(n)).

Différentes commandes sont disponibles pour :

  • démarrer un processus en arrière-plan : avec le symbole & à la fin de la commande

    $ xclock -update 1 &
    

  • endormir le processus en premier-plan : taper Ctrl+Z

  • terminer le processus en premier plan : taper Ctrl+C

  • réveiller le processus endormi et l'envoyer en arrière plan : $ bg

  • (réveiller le processus s'il est endormi et) l'envoyer en premier plan : $ fg

  • connaître la liste des commandes qui dépendent du shell courant : $ jobs

Lorsqu'il y a plusieurs jobs on peut préciser lequel on manipule via le jobspec : le caractère % suivi du numéro de job :

$ xclock & evince &
[1] 6266
[2] 6267
$ fg %2
evince
^Z
[2]+  Arrêté                evince
$ bg %2
[2]+ evince &
$ kill %2

En interne, ces changements d'états sont effectués à l'aide de signaux Unix :

  • SIGINT : Ctrl+C
  • SIGTSTP : Ctrl+Z
  • SIGCONT : fg et bg
  • SIGTERM : kill

4.5. Historique des commandes

Le shell bash garde un historique des commandes qui ont été exécutées en mode interactif.

L'historique est conditionnée par des variables internes :

$ echo $HISTSIZE
1000
$ echo $HISTFILE
/home/thiel/.bash_history
$ ls -l $HISTFILE
-rw------- 1 thiel thiel 43441 oct.   7 11:47 /home/thiel/.bash_history

Le fichier .bash_history est créé automatiquement par bash avec des droits restrictifs (il peut y avoir des mots de passe dans les commandes...).

Les flèches haut et bas permettent de naviguer dans l'historique.

La commande history affiche l'historique complet (à partir du fichier) :

$ history | tail -4
 2272  echo $HISTSIZE
 2273  echo $HISTFILE
 2274  ls -l $HISTFILE
 2275  history | tail -4

Il y a de nombreux raccourcis :

$ !!                        # Rappelle la dernière commande
history | tail -4
 2272  echo $HISTSIZE
 2273  echo $HISTFILE
 2274  ls -l $HISTFILE
 2275  history | tail -4

$ !2273                     # Rappelle la commande numéro
echo $HISTFILE
/home/thiel/.bash_history

$ !!:p                      # affiche la dernière commande sans l'exécuter
echo $HISTFILE
$ !2274:p                   # idem pour la commande numéro
ls -l $HISTFILE
Des raccourcis existent aussi pour les arguments :

!$ répète le dernier argument de la commande précédente
!^ répète le premier
!* répète tous les arguments

Exemple :

$ echo bonjour les amis
bonjour les amis
$ echo !$ !^
echo amis bonjour
amis bonjour

ou encore :

$ mkdir toto
$ cd !$
cd toto
toto$ 

En cours de saisie :

  • Ctrl+R texte   va chercher la dernière occurrence de texte dans l'historique ;
  • Ctrl+R   passe à la précédente, et ainsi de suite ;
  • Enter   la valide.
  • Ctrl+A   va au début de la ligne ;
  • Ctrl+E   va à la fin de la ligne.

Voir encore :