Petit Guide Unix


4. Les Commandes Sous Unix


Najib TOUNSI ( ntounsi@emi.ac.ma)
Last update: Oct 1998

PRECEDENT SOMMAIRE SUIVANT

La forme générale d'une (ligne) commande UNIX [5] est

% commande [options] [arguments]

où les arguments sont en général des fichiers, et les options des moyens de varier le traitement de la commande. Par exemple:

% ls -l employe departement
-rw-r--r-- 1 tounsi 805 Feb 20 15:16 employe
-rw-r--r-- 1 tounsi 556 Feb 20 15:17 departement

liste (ls) les caractéristiques des deux fichiers arguments (employe departement) en format long (option -l).

C'est très puissant comme principe dans la mesure où d'une part, un même nom de commande sert à designer une classe de traitements possibles (on varie l'option), et d'autre part, il suffit d'une légère modification du code (source C) de la commande pour augmenter ou varier ces traitements.

Par ailleurs, la plupart des commandes UNIX se comportent comme un filtre, ayant des données en entrée et des résultats en sortie [6] (données/résultats qui sont des fichiers textes).

4.1. Fichier stdin, stdout et stderr

Fig-6, Entrées/Sorties d'une Commande UNIX.
 

Ainsi donc, les données d'une commande UNIX proviennent d'un fichier de non logique stdin et ses résultats sont écrits dans un autre fichier de nom logique stdout. Le cas échéant, les messages d'erreurs seront eux écrits dans un fichier stderr (non représenté ici).  Ces trois fichiers (type texte) sont toujours présents et attachés à une commande UNIX. Par défaut, ces fichiers sont assignés au

Le clavier et l'écran  constituent les fichiers physiques correspondants. Cette caractéristique UNIX s'est avérée très pratique à l'usage. En fait, les arguments d'une commande consistent parfois en une simple réassignation des fichiers std*.Réassignation qui peut être faite de deux façons:

4.2. Redirections

Les fichiers stdin, stdout et stderr peuvent être réassignés à d'autres fichiers physiques que le claviers et l'écran. Le mécanisme de redirection du shell permet de

Dans ce dernier cas, les erreurs continuent, néanmoins, à sortir sur l'écran. Pour rediriger aussi les erreurs, il suffit de faire (sous csh)

commande ... >& fichierErreursResultats

Remarque: Pour séparer les erreurs des résultats il suffit de faire

(commande ...> fichierResultats ) >& fichierErreurs

i.e. exécuter dans un sous shell  la commande avec sortie des résultats . C'est le but des parenthèses.

La redirection > écrase, si il existe, le ficher sortie donné en argument. Si on veut rallonger celui-ci, il suffit d'utiliser >> sur le fichier sortie. Par ailleurs, la commande set noclobber permet d'éviter d'écraser (par mégarde) un fichier redirection sortie. noclobber est une variable shell de type booléen rendue vrai ou faux alternativement par set noclobber.

Exemples:

Les redirections constituent un mécanisme très puissant comme l'illustrent les exemples suivants avec la commande cat (catenate).

cat f1 f2 f3 ...

met les fichiers f1 f2 f3 ... bout à bout  et les imprime sur la sortie standard. Sans paramètres, cat lit sur son entrée standard. Ainsi on peut:

% cat f1
The human mind treats a new idea the way the body treats a strange protein --it rejects it.
-- P. Medawar
% cat <f1 >f2
% cat f2
The human mind treats a new idea the way the body treats a strange protein --it rejects it.
-- P. Medawar


Remarque: cat f1 >f2 fait la même chose (pourquoi?) [7].

% cat >f1
"f u cn rd ths u cn fnd a gd jb n cmptr prgrmmng"
^D
% cat f1
"f u cn rd ths u cn fnd a gd jb n cmptr prgrmmng"

cat >>fichier

et saisir des lignes, comme précédemment, qui viendront se rajouter en fin de fichier.

% cat >> f1        (comme précédemment)
... nouveau texte
^D
% cat f1 f2 >f2
cat: input f2 is output     (pas de "copie" de f2 sur lui-même!)
% cat f1 f2 >w
% cat w >f2

etc ....

Exercice: mettre des données en début d'un fichier texte existant.

Avant de terminer, sachez qu'il existe aussi une redirection

commande  ... << mot

qui veut dire que le fichier entrée stdin est le texte qui suit jusqu'au mot indiqué, seul et en début de ligne (cette technique s'appelle here document). Cela sert surtout dans un fichier script exécutable en différé (cf [[section]] 3.2.4.). L'exemple suivant est un script qui met un adage (commande fortune) dans le fichier /etc/motd (message of the day) qui s'affiche à chaque connexion.

ed -s /etc/motd <<'FIN'   <--- Editer le ficher /etc/motd.
5,$d                      <--- Commandes editions pour
w                         <--- supprimer les 5 dernières
q                         <--- lignes.
'FIN'                     <--- Fin de fichier entrée de ed
echo Message Du Jour >>/etc/motd
echo " " >>/etc/motd
/usr/demo/games/fortune >>/etc/motd

Le mot en question est 'FIN' ici. Il peut être aussi un caractère quelconque, point (.) par exemple.

4.3. Enchaînement de Commandes

Un point-virgule permet d'enchaîner plusieurs commandes consécutives.

cmd1 ; cmd2 ; ... ; cmdn

Exemple:

% pwd
/shems/users/tounsi/BOOKS/UNIX
% cd test ; pwd ; ls
/shems/users/tounsi/BOOKS/UNIX/test
data err res

Les commandes enchaînées ainsi sont totalement indépendantes. Le déroulement de l'une ne dépend pas des précédentes. Même si l'une se termine mal (sans boucler tout de même).

Remarque: à propos de dernier exemple, la deuxième ligne commande, peut servir pour définir un alias (voir alias plus loin) à la commande cd de changement de directory. Comme cela, à chaque changement de répertoire, le shell affiche le nom du nouveau répertoire avec son contenu.

4.4. Commandes Concurrentes: mécanisme de pipe

On peut aussi exécuter plusieurs commandes d'un coup, mais de façon concurrente cette fois-ci-- elles s'exécutent en quelque sorte en parallèle. Elles se déroulent de façon asynchrone sauf que la sortie standard de l'une des commandes est l'entrée standard de celle qui la suit. On écrit:

cmd1 | cmd2 ... | cmdn

Le symbole | désigne, outre le parallélisme, un mécanisme de tube (pipe) où tout ce qu'écrit une commande, est lu par la suivante, dans un ordre FIFO (le premier caractère écrit est le premier lu).

Fig-7, Commandes Liées par Tubes
 

Exemples:

% who | wc -l
4

La commande who affiche sur sa sortie standard, la liste des utilisateurs connecté(e)s (1 par ligne) et la commande wc -l calcule le nombre de lignes de son fichier entrée. La commande globale, who|wc -l, affiche 4 qui est dans ce cas, le nombre d'utilisateurs connecté(e)s.

% man man | head -23 | tail +19
man displays information from the reference manuals. It can display complete manual pages that you select by title, or one-line summaries selected either by keyword (-k), or by the name of an associated file (-f).

Cette ligne commande extrait les lignes de 19 à 23 du manuel (help) concernant la commande man. D'abord on sort le manuel (commande man, 1ère occurrence dans l'exemple), ensuite on en extrait les 23 premières lignes (commande head), desquelles on ne garde que les dernières à partir de la 19e (commande tail).

Le fait que les commandes en pipe se synchronisent sur leurs E/S standards, n'implique pas que l'une doit attendre que la précédente se termine. Sur l'exemple ci-dessus, head commence dès que man a écrit quelque chose sur le tube. De même, tail commence dès que head à produit une sortie. Inversement, une commande peut s'arrêter le temps que sa suivante vide la place dans le tube pour écrire.

Enfin, pour montrer que | permet une exécution parallèle, on a fait deux programmes qui ne lisent rien et impriment chacun un caractère différent (* pour l'un et . pour l'autre) sur leur sortie erreur standard (pour éviter une synchronisation sur le tube).

% cat P1.c
#include <stdio.h>
main(){ int i;
while(1){
for(i=0;i<123456;i++);
fprintf(stderr,"*");
}
}
% cat P2.c
#include <stdio.h>
main(){ int i;
while(1){
for(i=0;i<100000;i++);
fprintf(stderr,".");
}
}
% cc -o P1 P1.c
% cc -o P2 P2.c
% P1|P2
***.....**..****.*...*..***...*..*...***.*...*..**
**..***.....**..*...**...**..*.***.....***.*....**
.*..*..*..****.*..*..**..*.**..***.....*
.*.***.....**.***..**..*..*.*..**.**...**....**
.*.*..**...***.
%                               <---- Interruption  par ^C

où on voit que * et . sont sortis au hasard de l'allocation du processeur. (Les boucles for sont là pour simuler un autre traitement du programme).

4.5. Commandes avec Analyse des Paramètres.

Les arguments d'une commande (shell ou UNIX) sont des mots (chaînes de caractères) qui correspondent en générale à des noms de fichiers. Le shell offre des mécanismes de "paramétrage" facilitant grandement la description de ces noms.

Mécanisme d'Expansion

Il correspond à la description d'une liste de noms de fichiers par des motifs. Les caractères *, ?, [,], jouent un rôle spécial pour cela.

*

?

[xyz]

[x-z]

[!xyz]

signifie toute chaîne de caractères même vide.

un caractère quelconque. êtreêtre

énumération des caractères utiles entre crochets

intervalle (ordre ASCII) de caractères 

complément de l'énumération ou de l'intervalle

Par exemple, [a-z]*.c signifie tout nom de fichier commençant par une lettre minuscule et se terminant par .c, et ??[!xyz] signifie nom de trois caractères le dernier n'étant pas x, y ou z. A ce niveau, les caractères . et / ne sont pas couverts par l'expansion.

Mécanisme de Substitution

Il correspond à un remplacement d'un mot par un texte. On en a rencontré quelques exemples avec la commande echo au [[section]]1.2. Considérons d'abord la notion générale de chaîne de caractères shell. Une telle chaîne peut être délimitée par les trois caractères ' (simple quote), " (double quote) et ` (anti quote), qui déterminent le type de substitution à réaliser à l'intérieur de la chaîne:

'
 
 
 

"
 
 
 

`

La chaîne est protégée. Si un caractère spécial s'y trouve, il perd son sens. Comme le $ par exemple. Ainsi echo '$path' affiche $path. $ n'a pas le sens contenu d'une variable. Le caractère ' lui-même n'est cependant pas protégé. La chaîne 'aujourd'hui' n'est pas possible. Ecrire plutôt "aujourd'hui"

La chaîne est protégée. Si un caractère spécial s'y trouve, il perd son sens. Comme le $ par exemple. Ainsi echo '$path' affiche $path. $ n'a pas le sens contenu d'une variable. Le caractère ' lui même n'est cependant pas protégé. La chaîne 'aujourd'hui' n'est pas possible. Ecrire plutôt "aujourd'hui"

Ici, la chaîne est interprétée comme une commande, dont le résultat est la valeur de la chaîne. Ainsi `date` est la chaîne constituée par la date système (résultat de l'exécution de la commande date), `ls` est la chaîne constituée par la liste des noms de fichiers d'un répertoire.

Voici deux exemples intéressants de tels substitutions:

set prompt="$users@`hostname` >"
alias cd 'cd \*!; set prompt="`pwd` >" '

la deuxième nécessitant les trois types de quotes.

4.6. Les Alias

Les alias sont des surnoms donnés par l'utilisateur à une commande (pour en simplifier l'écriture par exemple). Le shell remplacera le surnom par la définition correspondante.

alias <surnom> <définition>

Un alias particulièrement intéressant est le remplacement de rm par rm -i qui demande confirmation avant chaque suppression de fichier. On écrit

alias rm rm -i

De même

alias ll ls -l

permet de taper ll au lieu de ls -l, qui affiche la liste des fichiers d'un directory avec toutes les informations qui les concernent.

Les alias sont propres à l'interprète de commandes où ils sont définis. Ils ne sont pas exportés. Sauf s'ils sont définis dans le fichier .cshrc qui est lancé pour chaque Cshell. En général, on les met dans le fichier .login, comme cela ils sont définis une fois pour toute.

Pour supprimer un alias on fait unalias. unalias ll détruit le surnom ll. unalias rm ne remplacera plus rm par rm -i. La commande alias tout court affiche les alias définis.

Dans la définition d'un alias, toute la chaîne qui suit le surnom constitue la définition de l'alias. Si cette chaîne doit comporter des métacaractères shell, il faut l'entourer de quotes (ou double quotes selon le principe déjà mentionné précédemment).

Exemples:

%alias h history
%alias bye logout
%alias adios logout
%alias wi who am i
%alias nbfiles 'ls | wc -l'

%alias
h history
bye logout
adios logout
wi who am i
nbfiles ls | wc -l

%wi
shems!tounsi ttyp1 Jul 6 15:20
%nbfiles
26

%alias nbfiles 'echo il y a `ls|wc -l` fichiers'
%nbfiles
il y a 26 fichiers

%unalias wi
%wi
wi: command not found

Il est possible de paramétrer les alias. En effet, comme une commande a des paramètres, on aimerait les transmettre à l'alias associé. Pour cela on utilise la chaîne \!: (l'antislash \ enlève sa signification au !), suivie du numéro du paramètre.

%alias ll ls -l\!:2
%ll p1.c p2.c p3.c
-rw-r--r-- 1 tounsi 715 Jul 22 17:50 p2.c

On peut aussi utiliser la forme \!:n-m pour les paramètres de n à m. Sinon, les formes \!$, \!^, \!* désignent respectivement le dernier, le premier ou toute la liste des paramètres.

alias cd 'cd \!*; pwd; ls'

permet d'afficher le nom du nouveau répertoire choisi par cd, et d'afficher les fichiers qu'il contient.

Pour les habitué(e)s du DOS, qui veulent rendre le prompt toujours égale au répertoire courant, il y a

% alias cd 'cd \!*; set prompt="`pwd` >"'
% cd
/shems/users/tounsi >cd rep
/shems/users/tounsi/rep >

Il ne faut pas trop abuser des alias, ils sont sources d'overhead.

4.7. Historique des Commandes

Le C-shell permet de mémoriser les commandes tapées et de les numéroter. On peut à tout moment rappeler une commande déjà faite localement au shell. !! rappelle la dernière commande faite, !chaîne rappelle la dernière ligne commande commençant par chaîne et !n rappelle la commande numéro n.

% cp a b
% cc -o exec p.c
% a.out

% !!
a.out

% !c
cc -o exec p.c

%!cp
cp a b

Les commandes sont numérotées à partir de 1 depuis le lancement d'un cshell. Le caractère ! (précédée de \) est le numéro d'une commande enregistrée.

% set prompt= '<\!> '
<22> who am i
shems!tounsi ttyp1 Jul 6 15:20
<23>

La variable d'environnement history doit être positionnée pour que le mécanisme de rappel fonctionne.

<23> set history = 50

sauvegarde jusqu'à 50 commandes. La commande history affiche les commandes accessibles.

<23> set history = 4
<24> cp a b
<25> cd c
<26> pwd
/shems/users/tounsi/c
<27> who am i
shems!tounsi ttyp1 Jul 6 15:20

<28> history
25 cd c
26 pwd
27 who am i
28 history

On peut aussi rappeler une commande par son numéro (s'il est encore accessible)

<29> !24
24: Event not found.
<30> !26
pwd
/shems/users/tounsi/c
<31>

Certains shells (Korn-shell ou tcsh, turbo csh) offrent un mécanisme agréable d'édition (emacs ou vi) des commandes rappelées. Sous csh c'est plus laborieux, car il utilise l'édition ligne comme ed. Pour remplacer une chaîne par une autre dans le rappel d'une commande on rajoute le caractère : suivi du remplacement.

<31> echo Mozart est ne an 1856
Mozart est ne an 1856
<32> echo 'OK?'
OK?
<33> !31:s/1856/1756/
echo Mozart est ne an 1756
Mozart est ne an 1756
<34>!!:s/an/en/
echo Mozart est ne en 1756
Mozart est ne en 1756

On peut ne retenir que certains mots d'une ligne commande:

<35> !31:0-2                   <--- les mots 0 à 2 de la ligne 31
echo Mozart est
Mozart est
<36> !31:0-2 le meilleur
echo Mozart est le meilleur
Mozart est le meilleur

On peut ainsi rallonger une ligne commande en la rappelant comme déjà vu et en tapant la rallonge juste après. Sachez enfin qu'il existe une variable d'environnement savehist qui, si initialisée à n, permet de sauvegarder dans le fichier .history les n plus récentes lignes commandes au moment du logout. Ce fichier initialisera l'historique pour la prochaine session.

4.8. La Gestion des Travaux (Jobs)

Background vs Foreground

Avant de discuter le mécanisme des jobs, regardons d'abord cette notion nouvelle. UNIX peut exécuter plusieurs choses simultanément. Quand on tape une commande, on attend qu'elle soit finie pour "reprendre la main". Ce n'est pas toujours nécessaire. On peut en effet exécuter une commande en arrière plan <<background>>, c'est à dire la laisser tourner tout en continuant sa session. C'est pratique quand la commande est assez longue et n'est pas interactive. Autrement on dit <<foreground>>, avant plan, pour le cas normal. Pour indiquer une exécution en background, il suffit de terminer la ligne commande par le symbole &. Exemple.

% find . -name hello.c -print &
[1] 10724
% echo on continue
on continue
%
./programme/hello.c
[1] Done find . -name hello.c -print
%

Il est demandé de rechercher un fichier hello.c et d'afficher son chemin d'accès. La recherche peut se révéler longue, on lance la commande en background avec &. Le système (le csh en fait) répond qu'il a numéroté 1 le travail demandé et lui a associé le processus 10724. La session se poursuit comme illustré par la commande echo. Dès que la recherche demandée est terminée, son résultat est affiché (./programme/hello.c), et le système répond que le travail, [1] donc, est terminé (Done).

Mécanisme de Jobs

Pour garder la trace des commandes en background (et d'autres), le shell associe un travail <<job>> numéroté à chaque ligne de commandes. Quand une ou plusieurs commandes sont tapées ensemble, comme pipeline ou comme une séquence de commandes séparées par point-virgule, le shell crée un simple job considérant ces commandes comme une seule unité ou tâche. Les commandes simples, sans pipe ni point-virgule, constituent le job le plus simple et il leur est associé un seul processus. Généralement chaque ligne tapée crée un job shell. Si le métacaractère & est tapée en fin de ligne, alors le job démarre en background. Le shell n'attend pas qu'il se termine, et invite à une autre commande.

Ce mécanisme permet, quand on lance plusieurs tâches simultanément, de suivre leur évolution sans avoir recours à la commande ps, qui dérange le noyau, et avec une numérotation plus simple que les numéros de processus. Cette numérotation est accessible par %n. La commande jobs permet d'afficher les numéros de toutes les tâches en cours.

Contrôle des Jobs

Une tâche en cours peut se trouver en trois états:

Un dernier état est celui où la tâche est terminée. On peut faire passer une tâche d'un état à un autre. Par exemple, une tâche en avant plan peut être stoppée par ^Z. Une tâche en arrière plan peut passer en avant plan par la commande

fg %n

n est le numéro du job associé. fg (pour foreground) sans numéro, met en avant plan le job courant (voir plus bas). Une tâche stoppée peut passer en background par

bg %n

L'exemple suivant illustre une commande (supposée longue) lancée en avant plan. Après avis on voudrait la passer en arrière plan. On la stoppe d'abord et on fait bg ensuite.

% find / -name latex -print
^Z
stopped

% jobs
[1] - Stopped emacs
[2] + Stopped find / -name latex -print

% bg %2
[2] find / -name latex -print &

% jobs
[1] + Stopped emacs
[2] Running find / -name latex -print
%

On peut aussi terminer un job en l'interrompant par une commande kill. Si ensuite on fait

% kill %2

on a comme réponse

[2] Terminated find / -name latex -print

et de façon général, kill -signal%n envoi le signal demandé au job référencé (voir man kill pour la liste des signaux, ou faire kill -l).

Le signe + ou - qui apparaissent dans l'exemple, indiquent par + le job dit courant (plus récemment stoppé ou mis en background), et par - le job dit précédent. Quand le job courant revient en avant plan ou est terminé, le job précédent devient le job courant.

Il existe aussi une commande stop [%n], qui stoppe le job courant ou celui de numéro donné.

En résumé, pour manipuler un job on a:

bg, fg, kill et stop pour respectivement mettre un job en arrière plan, en avant plan, le terminer (ou lui envoyer un signal) et pour le stopper

et pour référencer un job on a:

%, %+, %% pour le job courant
%- pour le job précédent
%?chaîne pour le job contenant chaîne dans sa ligne commande.

La figure suivante résume un peu la situation:

Fig-8, Graphe des Etats des travaux Unix

PRECEDENT SOMMAIRE SUIVANT