Chapitre 1: Introduction

Objectifs:

1.1) Principes fondamentaux de la programmation shell

Principes fondamentaux:
On souhaite présenter l'essentiel des syntaxes du shell telles qu'on les utilise classiquement dans des scripts "professionnels". En ce sens, on ne prétend pas être exhaustif et couvrir l'intégralité de certaines tournures syntaxiques.
Ce document comporte, en tant que tel, relativement peu d'exemples car il sera accompagné, par ailleurs, d'un nombre important d'exercices de mise-en-oeuvre.
On ne fera plus forcément la distinction entre le traditionnel "Bourne-shell" et les extensions apportées par le "Korn-shell" car on suppose que celui-ci est largement standardisé aujourd'hui et que son utilisation, dans le cadre de scripts d'entreprise, est tout à fait "dans les moeurs".

1.2) Documentation disponible

Documentation:
• Utilisation en système d'exploitation multi-tâche
• Complexe et puissant
• Nombreuses applications intégrées
• Grande collaboration avec le "Domaine Public"

1.2.1) Site Internet

1.2.2) Livres

• The New KornShell Command and Programming Language (Morris Bolksy & David Korn , Prentice Hall, 1995)
• Learning the KornShell (Bill Rosenblatt , O'Reilly & Ass~ 1993 au format électronique)
• Korn Shell Programming Tutorial (Barry Rosenberg , Addison- Wesley, 1991)
• Langages de scripts sous Linux (Blaess, Eyrolles, 12/2001 )
• La programmation sous Unix 3ème éd (JM Rifflet)



Chapitre 2: Notions de base en shell

Objectifs:
• Rappels sur l'entrée en session
• Fichiers de démarrage

2.1) Rappel sur l'entrée en session

Entrée en session:
• Mode commande
• Interface Graphique: CDE, Gnome, KDE

2.2) Étude des différents fichiers de démarrage

Fichiers de démarrage:
• Entrée en session
• Démarrage d'un nouveau processus
• Fin de session
• Shell: interpréteur de commandes
• Shell: langage de programmation

Une connexion consiste en un processus correspondant à l'exécution d'un shell. Ce shell est celui choisi par l'administrateur lors de la création du compte. L'utilisateur peut demander à l'administrateur de changer de shell.
Ce shell est à la fois un interpréteur de commandes et un langage de programmation permettant l'écriture de procédures utilitaires et constituant un des outils de travail de l'administrateur.
Les shells essentiels du monde UNIX sont, dans l'ordre chronologique:
• Bourne-shell (natif, est de base /bin/sh administrateur UNIX)
• C-shell
• Korn-shell ( /bin/ksh utilisateur UNIX)
• Posix Shell ( version normalisée du Korn-Shell retenue par l'organisme X/Open)
• Bash ( pour Bourne Again Shell : le shell de Linux ) /bin/bash deviendra à terme le shell UNIX
• tcsh
• Z-shell

Dans la suite, les références au shell sont celles des environnements Korn-shell bien standardisés aujourd'hui.

2.3) Variables et environnement


La notion de variable concerne surtout l'aspect programmation. Cependant, il existe un certain nombre de variables système prédéfinies ayant un rôle important vis à vis de l'utilisateur interactif.
Une variable shell contient une chaîne de caractères quelconque. Son nom peut être constitué de lettres, de chiffres et du caractère _ (souligné) , il ne peut pas commencer par un chiffre (conventions des identificateurs du langage C).

• Le caractère = (signe égal) est le symbole d'affectation de variable.
• Le caractère $ permet de désigner la valeur d'une variable.

La commande unset permet d'annuler la définition d'une variable:
prabou@prabou-VPCZ23C5E:~$ mavariable=ambre
prabou@prabou-VPCZ23C5E:~$ echo $mavariable
ambre
prabou@prabou-VPCZ23C5E:~$ unset mavariable
prabou@prabou-VPCZ23C5E:~$ echo $mavariable

prabou@prabou-VPCZ23C5E:~$


Par conventions:
-les variables locales sont en minuscules (uniquement dans le shell)
-les variables globales sont en majuscules (shell et sous-shells)

On peut donc créer deux variables différentes "toto" et "TOTO" qui sont bien différentes, d'où l'importance de prendre des noms différents.
var=valeur et ensuite pour la rendre globale il faut exporter cette variable avec export var
On peut aussi le faire en une seule commande avec export VAR=valeur

2.4) Notion d'environnement : instruction export


L'environnement shell (variables exportées) est constitué de l'ensemble des variables qui sont transmises à un processus" fils" par le mécanisme de "fork".
Une variable non exportée n'est pas connue dans le processus fils. Les modifications, dans les processus fils, des variables exportées s'opèrent sur des copies locales et n'altèrent donc en rien les valeurs des variables dans le processus "parent".

2.4.1) Liste des variables

Afficher la liste de toutes les variables, celles de l'environnement et celles qui ne s'y trouvent pas.

$ set | more
LANG=C
PATH=/usr/bin:/usr/bin/X11
EDITOR=/usr/bin/vi
...

2.4.2) Afficher la liste des variables d'environnement

prabou@prabou-VPCZ23C5E:~$ env | more
SHELL=/bin/bash
SESSION_MANAGER=local/prabou-VPCZ23C5E:@/tmp/.ICE-unix/1335,unix/prabou-VPCZ23C5E:/tmp/.ICE-unix/1335
WINDOWID=29360135
QT_ACCESSIBILITY=1
COLORTERM=truecolor
XDG_CONFIG_DIRS=/etc/xdg/xdg-plasma:/etc/xdg:/usr/share/kubuntu-default-settings/kf5-settings
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session1
LANGUAGE=fr
MANDATORY_PATH=/usr/share/gconf/plasma.mandatory.path
SSH_AUTH_SOCK=/tmp/ssh-lTaDZUjJQ7vy/agent.1216
SHELL_SESSION_ID=cd276a176dc844ed8af12184e843d95c
DESKTOP_SESSION=plasma
LC_MONETARY=fr_FR.UTF-8
SSH_AGENT_PID=1274
GTK_RC_FILES=/etc/gtk/gtkrc:/home/prabou/.gtkrc:/home/prabou/.config/gtkrc
XDG_SEAT=seat0
PWD=/home/prabou
XDG_SESSION_DESKTOP=KDE
LOGNAME=prabou
XDG_SESSION_TYPE=x11
GPG_AGENT_INFO=/run/user/1000/gnupg/S.gpg-agent:0:1
XAUTHORITY=/tmp/xauth-1000-_0
GTK2_RC_FILES=/etc/gtk-2.0/gtkrc:/home/prabou/.gtkrc-2.0:/home/prabou/.config/gtkrc-2.0
HOME=/home/prabou
LANG=fr_FR.UTF-8
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=
01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=0
1;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=
01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;3
5:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.as
f=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m
4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
XDG_CURRENT_DESKTOP=KDE
KONSOLE_DBUS_SERVICE=:1.100
KONSOLE_DBUS_SESSION=/Sessions/1
PROFILEHOME=
TMPDIR=/tmp
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
KONSOLE_VERSION=181203
KDE_SESSION_UID=1000
LESSCLOSE=/usr/bin/lesspipe %s %s
XDG_SESSION_CLASS=user
TERM=xterm-256color
DEFAULTS_PATH=/usr/share/gconf/plasma.default.path
LESSOPEN=| /usr/bin/lesspipe %s
USER=prabou
COLORFGBG=15;0
KDE_SESSION_VERSION=5
PAM_KWALLET5_LOGIN=/run/user/1000/kwallet5.socket
DISPLAY=:0
SHLVL=0
LC_MEASUREMENT=fr_FR.UTF-8
XDG_VTNR=1
XDG_SESSION_ID=3
GS_LIB=/home/prabou/.fonts
XDG_RUNTIME_DIR=/run/user/1000
LC_TIME=fr_FR.UTF-8
QT_AUTO_SCREEN_SCALE_FACTOR=0
LC_COLLATE=fr_FR.UTF-8
XCURSOR_THEME=breeze_cursors
XDG_DATA_DIRS=/usr/share/plasma:/usr/local/share:/usr/share:/var/lib/snapd/desktop
KDE_FULL_SESSION=true
PATH=/home/prabou/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
KONSOLE_PROFILE_NAME=Par défaut
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
LC_NUMERIC=fr_FR.UTF-8
KONSOLE_DBUS_WINDOW=/Windows/1
_=/usr/bin/env
prabou@prabou-VPCZ23C5E:~$


Déclarer une variable d'environnement:
prabou@prabou-VPCZ23C5E:~$ env | grep variable
prabou@prabou-VPCZ23C5E:~$ variable=valeur
prabou@prabou-VPCZ23C5E:~$ export variable
prabou@prabou-VPCZ23C5E:~$ env | grep variable
variable=valeur
prabou@prabou-VPCZ23C5E:~$

Note: Avec le ksh la syntaxe directe export variable=valeur est possible.

2.5) Quelques variables système


Certaines variables ont un rôle plus ou moins important pour l'utilisateur du shell.
Ces variables système peuvent avoir une valeur par défaut ou être initialisées à diverses étapes de la procédure de connexion. A ce niveau, l'administrateur doit décharger au maximum le travail de l'utilisateur.
Variable Description
PATH Liste des noms de répertoires dans lesquels le système cherche les commandes.
PS1 Prompt principal ($ par défaut).
PS2 Prompt secondaire (> par défaut). Le prompt secondaire apparaît si la commande doit se continuer sur la ligne suivante.
TERM Type du terminal (émulation). Une bonne valeur est nécessaire notamment au bon fonctionnement de vi
EDITOR Editeur indirect utilisé par certains utilitaires nécessitant une édition.
HOME Nom complet du répertoire de connexion.
LOGNAME Nom de connexion
PWD Nom du répertoire courant. Cette variable est tenue à jour par la commande cd
OLDPWD Nom du répertoire courant précédent (on peut utiliser la commande cd - pour y retourner; spécifique au ksh)
PPID Valeur du PID du processus père (spécifique au ksh)
TMOUT Nombre de secondes d'inactivité, sous le prompt du shell, avant déconnexion (TMOUT=0 - pas de déconnexion; spécifique au ksh)

Autres variables utiles gérées par le shell:
Variable Description
$ PID du shell interpréteur
! PID du dernier fils lancé en arrière-plan
? Code de retour de la dernière commande appelée


2.5.1) Exemples d'utilisation
Avoir comme prompt principal le nom du répertoire courant:
$ PS1='$PWD $ '
/home/stagel $ cd ..
/home $ cd

Redéfinir le prompt secondaire:
$ PS2='suite : '
echo "bonjour cher
suite : ami"
bonjour cher
ami

Gérer le PATH et le mettre à jour si besoin:
$ echo $PATH
/usr/bin:/usr/bin/X11
$ mount
ksh : mount : not found
$ /usr/sbin/mount
/ on /dev/root read/write/setuid on Nov 25 16 :03 :29
/stand on /dev/dsk/c0t0d0sa read/write on Nov 25 16 :03 :30
/home on /dev/dsk/c0t0d0s4 read/write/setuid on Nov 25
16 :03 :43
...
$ PATH=$PATH:/usr/sbin
$ echo $PATH
/usr/bin:/usr/bin/X11:/usr/sbin
$ mount
/ on /dev/root read/write/setuid on Nov 25 16 :03 :29
/stand on /dev/dsk/c0t0d0sa read/write on Nov 25 16 :03 :30
/home on /dev/dsk/c0t0d0s4 read/write/setuid on Nov 25
16 : 03 :43
…

Annuler la définition de la variable TERM:
$ unset TERM
$ vi
Visual needs addressable cursor or upline capability
:q
$ TERM=bidon; export TERM
$ vi
bidon : Unknown terminal type
Visual needs addressable cursor or upline capability
:q
$ TERM=vt100
$ export TERM


2.6) Compléments sur les variables

On sait que la valeur d'une variable est donnée par le symbole $. Des notations complémentaires sont disponibles pour permettre de lever des ambiguïtés syntaxiques, et récupérer la taille des variables.
${var} permet d'opérer correctement des concaténations:
prabou@prabou-VPCZ23C5E:~$ nom=ambre
prabou@prabou-VPCZ23C5E:~$ var=systems
prabou@prabou-VPCZ23C5E:~$ echo $nom
ambre
prabou@prabou-VPCZ23C5E:~$ echo $var
systems
prabou@prabou-VPCZ23C5E:~$ echo $nom_$var
systems
prabou@prabou-VPCZ23C5E:~$ echo ${nom}_$var
ambre_systems
prabou@prabou-VPCZ23C5E:~$

${#var} permet d'obtenir la longueur d'une variable:
prabou@prabou-VPCZ23C5E:~$ echo $HOME
/home/prabou
prabou@prabou-VPCZ23C5E:~$ echo ${#HOME}
12
prabou@prabou-VPCZ23C5E:~$


2.7) Initialisation de variables


varlen=${#var}                     longueur d'une variable
var=${varl:-value}                     var=var1 si var1 est positionné, var=value si var1 n'est pas positionnée ou vide
var=${var1:=var2}                     var= $var1 si var1 est positionné et non vide, sinon = $var2
var=${varl=var2}                     var=$var1 si var1 est positionné, même s'il est vide, sinon = $var2
var=${varl:+var2}                     var=$var2 si varl est positionné et non vide, sinon var n'est pas positionné
var=${var1:+var2}                     var=$var2 si var1 est positionné même s'il est vide, sinon var n'est pas positionnée
var=${varl: ?}                     var=varl si varl est positionnée, sinon, on a un message d'erreur
var=${var1: ?var2}                     var=var1 si var1 est positionnée, sinon var=var2 et quitte

2.8) Caractères spéciaux

Une des premières fonctions du shell est d'interpréter un certain nombre de caractères avant l'appel des commandes. Il est à noter que les commandes Unix ne traitent pas les caractères spéciaux.
Elles héritent d'une liste de paramètres déjà résolue et ne se préoccupent pas de mécanismes comme les redirections ou le "pipeline". Ce principe de base favorise grandement l'activité de programmation et s'inscrit parfaitement dans la démarche "boîte à outils" modulaire voulue par les concepteurs du système.

Rappel des caractères déjà évoqués:
Caractère Description
< Redirection de l'entrée standard
> et >> Redirections de la sortie standard
2> et 2>> Redirections de l'erreur standard
; Processus séquentiels
| Mécanisme du "pipeline"
& Mode arrière-plan
( ) Grouper des commandes
= Affectation de variable
$ Contenu d'une variable

Expressions génériques simples:
Caractère Description
* N'importe quelle chaîne dans un nom de fichier Utilisé seul, signifie : "Tous les fichiers du répertoire courant" (ne sélectionne pas les fichiers commençant par . (point))
? Présence d'un caractère quelconque dans un nom de fichier
[ensemble_de_caractères] Présence d'un caractère de l'ensemble
[!ensemble_de_caractères] Présence d'un caractère ne figurant pas dans l'ensemble

Exemple:
$ touch fic1 fic2 essai99 fic.txt exemple
$ echo *
fic1 fic2 essai99 essai99 fic.txt exemple
$
$ echo .[!.]*
.profile
. sh_history

Remarque:
Après un unset PATH, les ls sont "not found", alors que la commande pwd fonctionne, car elle est intégrée au shell. Il faudra alors par exemple ouvrir un autre terminal (voir le fichier /etc/profile qui définit PATH).

2.8.1) Expressions génériques composées du Korn-shell

En complément aux expressions génériques simples (ci-dessus) largement utilisées, les notations suivantes existent en Korn-shell :
Caractère Description
*(expr1|expr2|...) Un nombre quelconque d'apparitions d'une des expressions (éventuellement aucune)
+(expr1|expr2|...) Un nombre quelconque d'apparitions d'une des expressions (au moins une)
?(expr1|expr2|...) Au plus une apparition d'une des expressions
@(expr1|expr2|...) Exactement une des expressions
!(expr1|expr2|...) Aucune des expressions

Exemples:
Caractère Description
*([A-Z]|[0-9]) Le résultat de la commande est inséré dans la liste d'arguments
+([A-Z]|[0-9]) Chaîne dont chaque élément est soit une majuscule soit un chiffre (chaîne vide exclue)
?([A-Z]|[0-9]) Chaîne vide ou d'un élément qui est soit une majuscule soit un chiffre
@([A-Z]|[0-9]) Chaîne d'un élément qui est soit une majuscule soit un chiffre
!([A-Z]|[0-9]) Chaîne ne comportant ni majuscule ni chiffre

Remarques:
' ': simples côtes, à l’intérieur rien n’est interprété
" ": doubles côtes, à l’intérieur rien n’est interprété sauf $, " et `
` `: interprété et remplacé par son résultat
Le double caractère est intéressant dans l’exemple: echo "l’histoire $PATH"

2.8.2) Substitutions de commandes

Caractère Description
`commande` Le résultat de la commande est inséré dans la liste d'arguments
$(commande) Syntaxe recommandée

prabou@prabou-VPCZ23C5E:~$ rep=`pwd`
prabou@prabou-VPCZ23C5E:~$ echo "Repertoire courant : $rep"
Repertoire courant : /home/prabou
prabou@prabou-VPCZ23C5E:~$ echo "Il est $(date +%H:%M:%S)"
Il est 16:46:58
prabou@prabou-VPCZ23C5E:~$


2.8.3) Caractères de protections

Caractère Description
\ Le caractère qui suit perd son rôle fonctionnel
' ' Tous les caractères situés entre les simples quotes perdent leur rôle fonctionnel
" " Tous les caractères situés entre les doubles quotes perdent leur rôle fonctionnel sauf $ (valeur de variable) et `` (résultat de commande). Mais il y a possibilité de banaliser $ et '

Afficher ou non le caractère *:
$ echo *
fic1 fic2 essai99 fic.txt
$ echo \*
*

Annuler ou non la substitution de commandes:
$ echo "La date est `date`"
La date est Mon Jan 03 15 :58 :39 GMT 2000
$ echo 'La date est `date`'
La date est `date`

2.8.4) Procédures et paramètres

Des séquences de commandes et d'instructions shell peuvent être regroupées dans un fichier qui devient ainsi une nouvelle commande ou "procédure" ou "script".

2.9) Structure et exécution d'un script shell


Un script shell peut contenir de manière générale:
• Une ligne de désignation de l'interpréteur
• des commandes UNIX, des commandes internes shell
• des structures de contrôle (instructions conditionnelles, boucles, aiguillages, etc ...)
• des commentaires

L'exécution est demandée de manière implicite en appelant le nom du script:
$ vi prog.ksh
#!/bin/ksh
#-- commentaires --
…
#-- code –- … exit 0
$ chmod +x prog.ksh #on attribue les droits d'execution pour le script prog.ksh
$ ./prog.ksh

2.10) Commentaire et shell interpréteur d'un script

Le caractère # introduit un commentaire jusqu'à la fin de la ligne en cours (il n’existe pas de caractère(s) de début et fin de commentaire).

Par défaut, le script est interprété par un shell fils du shell de connexion et ne reçoit que les variables de l'environnement validées grâce à l'instruction export. La première ligne du script (parfois appelée shebang ou directive d'exécution) est importante car elle permet d'indiquer l'interpréteur choisi pour l'exécuter. Si cette ligne est omise, le shell interpréteur choisi sera par défaut le même que le shell interactif d'où est lancé l'exécution. Il est recommandé de toujours faire apparaître explicitement cette désignation de l'interpréteur.
Remarque: un avantage de nommer un programme *.sh c’est qu’on évite une commande UNIX par défaut.

2.11) Code retour et traitement associé

Les scripts peuvent retourner un code retour via l'instruction de sortie exit n . La tradition est de retourner 0 en cas de succès et une valeur dans l'intervalle [1 , 255] sinon.
Exemple: sortir du script en retournant la valeur 3
$ cat prog.ksh
#!/usr/bin/ksh
…
exit 3
$ ./prog.ksh
$ echo $?
3

2.12) Interprétation d'une ligne de commande

Le shell interprète chaque ligne d'un script suivant un ordre donné:
• Substitutions de variables,
• Substitutions de commandes,
• Traitement des redirections et tubes,
• Traitement des caractères spéciaux sur les noms de fichiers,
• Appel de la commande (via "fork") ou de l'instruction.

2.13) Paramètres du script

Il est possible de fournir de l'information au script lors de son exécution en utilisant des paramètres (ou arguments) sur la ligne de commande. Les valeurs saisies (chaînes de caractères) sont automatiquement mises dans les variables système 1, 2, 3, 4, ...
Les variables complémentaires # et * contiennent alors respectivement le nombre de paramètres saisis et la liste concaténée de tous les paramètres.

Exemple 1 - procédure élémentaire gérant les paramètres de la ligne de commandes:
prabou@prabou-VPCZ23C5E:~$ cat prog.sh
#!/bin/bash
echo "Premier argument : $1"
echo "Nombre d'arguments: $#"
echo "Liste des arguments : $*"
exit 0

# Résultat de l'exécution
prabou@prabou-VPCZ23C5E:~$ ./prog.sh un deux quatre
Premier argument : un
Nombre d'arguments: 3
Liste des arguments : un deux quatre
prabou@prabou-VPCZ23C5E:~$


Exemple 2 - procédure élémentaire affichant la taille en octets du fichier passé en premier argument, et retournant le code 3 d'erreur sinon:
$ cat preg.ksh
#!/usr/bin/ksh
echo "Taille du fichier: $(wc -c $1)"
exit 0

Résultat de l'exécution lorsque le fichier exemple existe:
$ prog.ksh exemple
Taille du fichier : 1242 exemple
$ echo $?
0




Chapitre 3: Programmation shell

Objectifs:
• Instructions conditionnelles - if/then/else
• Traitement des flux - for, while, until
• Lecture au clavier
• Expressions arithmétiques
• Branchements - case
• Fonctions

3.1) Instructions conditionnelles et tests

Instructions conditionnelles:
• if/then/else
• Structure essentielle de contrôle

3.1.1) L'instruction if
• Syntaxe:
if commande 
then
	liste_de_commandes
fi

ou

if commande ; then 
	liste_de_commandes
fi

ou
 
if 	commande 
then 
	liste_de_commandes 
else 
	liste_de_commandes
fi 

Note: Il est possible de placer plusieurs commandes après le "if". Dans ce cas, le test prend en compte le code retour de la dernière de ces commandes.
Exemples simples de syntaxe:
if who | grep stage1 > /dev/null ; then echo "stage1 est connecte" fi
a=1 if [ $a –eq 1 ] then echo "a=$a" fi
if date ; who | grep root > /dev/null then echo "root est connecte" else echo "root n'est pas connecte" fi
3.1.2) Instructions conditionnelles composées : if imbriqués
• Syntaxe:
if 	commande 
then 
	liste_de_commandes 
else if commande 
     then
		liste_de_commandes 
     else if commande
	  then
			liste_de_commandes 
	  else 	#Ce "else" est bien sur facultatif 
			liste_de_commandes 
	  fi
     fi 
fi

Attention! L'utilisation de la syntaxe en deux mots else if nécessite autant de fi que de if.
Autre forme (lif) (ne nécessite qu'un seul "fi" fermant):
if	commande 
then 
	liste_de_commandes 
elif	commande 
	then 
		liste_de_commandes 
	elif 	commande 
	then
		liste_de_commandes
 
else	#Ce "else" est bien sur facultatif 
	liste de commandes 
fi 

3.1.3) Instructions conditionnelles compactes: opérateurs && et ||
Ces notations exploitent le code retour. Elles permettent de faire des instructions conditionnelles sur une ligne.
• cde1 && cde2 Lancer la deuxième commande si la première a réussi (exit 0).
• cde1 || cde2 Lancer la deuxième commande si la première a échoué ( exit avec code retour différent de 0 ).
• $? Code retour de la dernière commande appelée.

Exemples:
$ ( who | grep stage1 ) || echo "stage1 non connecte"
stage1 non connecte
$ ls exemple > /dev/null 2>&1 && lp exemple	#lp redirection vers l'imprimante

3.1.4) La commande test
La commande test, les [ ] et les [[ ]]:
• Utilisation de la commande test
• Utilisation des [ ]
• Utilisation des [[ ]] (Korn Shell)

Cette commande évalue une expression booléenne et retourne la valeur 0 si cette expression est vraie.
Il s'agit donc d'une commande assez indispensable pour réaliser certains tests via les instructions du shell.
test 	expression
ou 
[ expression ]

Note: Les crochets doivent être délimités par des espaces.

Quelques expressions possibles:
Expression Description
"chaîne1"="chaîne2" Les deux chaînes sont identiques
"chaîne1"!="chaîne2" Les deux chaînes sont différentes
-z "chaîne" La chaîne est de longueur nulle
-n "chaine" La chaîne est de longueur non nulle
entier1 -eq entier2 Les deux entiers sont égaux
Autres opérateurs "entiers" -ne -gt -ge -lt -le
-e fichier Le "fichier" existe (on peut aussi utiliser - a, mais considéré comme obsolète).
-r fichier Droit de lecture sur "fichier"
-w fichier Droit d'écriture sur "fichier"
-x fichier Droit d'exécution sur "fichier"
-u fichier Le bit SUID est positionné
-g fichier Le bit SGID est positionné
-k fichier Le "sticky bit" est positionné
-f fichier Il s'agit d'un fichier ordinaire
-d fichier Il s'agit d'un répertoire
-c fichier Il s'agit d'un fichier spécial de type caractère
-b fichier Il s'agit d'un fichier spécial de type bloc
-L fichier Il s'agit d'un lien symbolique
-s fichier Le fichier est de taille non nulle
! Négation
-o OU
-a ET (plus prioritaire que le OU)

Exemples simples de syntaxe:
if 	test $# -eq 0 ;	then
	echo "Usage: $0 argument"; exit 1 
fi
ou encore:
if 	test $# -eq 0 ### ou [ $# -eq 0 ] 
then
	echo "Usage: $0 argument" 
	exit 1 
fi

if	test -f $1 
then
	echo "$1 est un fichier ordinaire"
elif	[ -d $1 ]
then
	echo "$1 est un repertoire"
elif	[ -L $1 ]
then
	echo "$1 est un lien symbolique"  
else 
	echo "Ni fichier ordinaire, ni repertoire, ni lien symbolique"
fi

 
if 	test -f $1 -a -x $1
then
echo "$1 est un fichier ordinaire et executable"
fi 

midi=12 
heure=`date '+%H'`

if 	test $heure -ge $midi
then
	echo "Il est plus de midi" 
else 
	echo "Il n'est pas encore midi" 
fi 

if [ ! -d $1 -a ! -L $1 ] ; then
	echo "$1 ressemble a un fichier ordinaire"
fi

Remarques:
- man test affichera toutes les options
- il faut un espace après le [ et avant le ]

3.1.5) Enrichissement de la commande test du Korn-Shell
Le ksh introduit quelques nouvelles expressions intéressantes:
Expression Description
-O fichier Est-on propriétaire du fichier?
-G fichier On fait partie du groupe propriétaire du fichier?
fic1 -nt fic2 Le premier fichier est-il plus récent que le deuxième fichier?
fic1 -ot fic2 Le premier fichier est-il plus ancien que le deuxième fichier?
fic1 -ef fic2 S'agit-il de deux liens sur le même fichier physique?

Exemple:
if [ $1 -ot $2 -a $3 -ef $2 ] 
then 
echo "$1 est plus ancien que $2" 
echo "$2 et $3 sont deux liens sur le meme fichier"
fi

Une nouvelle syntaxe est possible en ksh
[[ expression ]]

L'intérêt essentiel de cette nouvelle syntaxe est la possibilité d'utiliser des expressions génériques (simples ou composées). L'analyse sémantique de chaînes de caractères sera désormais possible dans l'instruction de test.
Par ailleurs les opérateurs logiques ET et OU sont remplacés par:
|| OU (remplace l'opérateur -o)
&& ET plus prioritaire que le OU (remplace l'opérateur -a)

Exemple de syntaxe:
#!/usr/bin/ksh
if [[$option = @(+|-)+([a-z]) && $var = ?(+|-)+([0-9]) ]]
then
...
fi


3.2) Traitement sur flux: les boucles


3.2.1) La boucle for
Cette boucle permet d'exécuter plusieurs fois une liste de commandes. A chaque pas de boucle, la variable choisie comme indice prend une valeur dans une liste donnée.
for variable in liste_de_valeurs
do 
	liste_de_commandes 
done
Quelques exemples
1) Boucler sur tous les paramètres de la procédure
for i in $*
do 
	liste_de_commandes
done
Note: La première ligne de cette boucle peut s'abréger en for i

2) Boucler sur tous les noms de fichiers du répertoire courant
for i in *
do
	liste_de_commandes 
done

3) Faire cinq fois un traitement
 
for i in 1 2 3 4 5 
do 
liste_de_commandes 
done

3.2.2) Les boucles while et until
La boucle while permet d'exécuter une liste de commandes tant qu'une condition est réalisée. La boucle until permet d'exécuter une liste de commandes jusqu'à ce qu'une condition soit réalisée.
while condition_r\'ealis\'ee
do 
	liste_de_commandes
done
ou
until condition_r\'ealis\'ee
do 
	liste_de_commandes
done

Exemple de syntaxe:
who | grep $1 >	/dev/null
while [ $? -eq 0 ]
do
 echo "$1 est connecte"
 sleep 15
 who | grep $1 > /dev/null 
done
echo "$1 n'est pas ou n'est plus connecte"
exit 0


3.2.3) Instructions de branchement
Il est possible d'utiliser des instructions de branchement pour sortir brutalement des boucles ou pour sauter les instructions restantes du corps de boucle:
break [ n ]: Quitter brutalement une boucle. L'éventuel paramètre n permet de quitter n niveaux de boucles imbriquées.
continue [ n ]: Retourner au test ( while et until ) , passer à la valeur suivante ( for).( éventuellement pour n niveaux)

Exemples:
• Ne pas faire la deuxième partie du traitement pour la 5ème itération de la boucle:
while [$i -lt 100 ] 
do
	...
	if [ $i = 5 ] ; then 
		continue 
	fi
	... 
done

• Quitter la 2ème boucle imbriquée au premier répertoire trouvé:
while 	true 							
do
	...						
	for f in *.txt 			
	do
		if [[ -d $f ]] 
		then
			break 2 
		fi
		...				
	done
done

3.3) Lectures au clavier : read

Syntaxe: read liste_de_variables
Cette commande lit une ligne au clavier. Par exemple:
#!/usr/bin/ksh 
echo "Entrez la valeur : \c" 
read var
echo "Vous avez saisi la valeur $var" 
exit 0

Dans le cas où la commande read a plusieurs variables en arguments, la ligne lue au clavier est "découpée" en champs. Le séparateur par défaut en lecture est : espace ou tabulation.
#!/usr/bin/ksh 
echo "Entrez les valeurs: \c" 
read i j k
echo "valeur de i: $i" 
echo "valeur de j: $j"
echo "valeur de k: $k"

Exécution:
$ prog.ksh 
Entrez les valeurs: 12 4 143 (saisie clavier) 
valeur de i: 12 
valeur de j: 4 
valeur de k: 143

Note : Dans la commande" test notamment, il est important de gérer la possible "lecture vide" en utilisant judicieusement les doubles quotes ou via un test préalable. Il convient en effet de toujours fournir le nombre d'arguments attendus à cette commande.

3.3.1) Nouvelles possibilités en Korn-shell
On peut poser une question et lire la réponse en une seule instruction. Par exemple:
read reponse? "Voici la question? "
équivaut à
echo "Voici la question? \c"; read reponse

3.4) Expressions arithmétiques

3.4.1) La commande expr (Bourne shell)
La commande expr permet d'interpréter des variables shell comme des entiers dans le cadre d'une expression numérique. Le résultat de cette évaluation peut être stockée dans une variable résultat via l'opérateur de substitution de commande.
Les opérateurs disponibles sont: + - * / ( division entière) % ( modulo )
while [ $n -lt 100 ] 
do 
	..traitement...
	n='expr $n + 1'
done

a=5 ; b=11 
mult='expr $a \* $b' 
div='expr $a / $b'

3.4.2) Expressions arithmétiques Korn shell
Le Korn-Shell possède une commande interne qui permet d'évaluer des expressions arithmétiques. Les opérateurs utilisables sont proches de ceux du langage C.
Syntaxe: let expression ou (( expression ))
Exemples de syntaxe:
_________________________________________________
x=10
let x=x+1:
On ne doit pas utiliser d'espaces avec la commande let
_________________________________________________
x=3
(( x=x*2 ))
Les doubles parenthèses permettent de mettre des espaces
_________________________________________________
x=3
(( x=(x-2)*3 ))
Les parenthèses modifient les priorités des opérateurs
_________________________________________________

3.4.3) Possibilités complémentaires
• let et (( )) peuvent être utilisées directement dans un test, afin d'effectuer des comparaisons numériques. Il faut alors utiliser les notations <, <=, >, >= (issues du langage C).
while (( i < 100 )) 
do
	...
done

• integer peut être utilisée pour déclarer des variables comme des entiers; cela permet de bâtir une expression "entière" directement:
integer i=0
i=i+1
Note: integer est un alias de la commande typeset -i.

3.5) Branchements


3.5.1) Instruction case
Syntaxe:
case valeur in 
	motif1)		liste_de_commandes
	;;
	motif2)		liste_de_commandes
	;;
	.......
esac

Les différents motifs sont examinés dans l'ordre. Si un des motifs correspond à la valeur de test, la liste de commandes correspondante est exécutée et il y a ensuite sortie de l'instruction.
Les motifs peuvent contenir des expressions génériques simples ou composées.
On peut citer notamment:
Le caractère | (pipe) peut être utilisé pour réaliser un OU.
Le motif * peut être utilisé comme dernier motif et jouer ainsi le rôle de "cas par défaut".

Exemple simple de syntaxe:
#!/usr/bin/sh 
case	$#	in 
	1|2) 	echo "On a recu 1 ou 2 arguments"
		echo "on enchaine apres l'aiguillage"
		;;
	3) 	echo "On a recu 3 arguments"
		echo "on enchaine apres l'aiguillage"
		;;
	*) 	echo "Mauvais appel, il faut 1 ou 2 ou 3 arguments"
		exit 1
		;;
esac 

echo "Suite du traitement"
exit 0

3.5.2) Instruction select du Korn-Shell
Cette instruction est proposée pour programmer des menus.
Elle se comporte comme une boucle et enchaîne les opérations suivantes:
• Affichage d'une suite de libellés numérotés automatiquement,
• Affichage de la variable système PS3,
• Lecture clavier du choix de l'utilisateur,
• La valeur d'index est positionnée avec le libellé correspondant au choix et la variable système REPLY contient le numéro correspondant. En cas de choix impossible, la valeur d'index contient la chaîne vide. En cas de réponse vide, le menu est réaffiché.

Syntaxe:
select variable in liste de libelles 
do 
	Aiguillage sur $variable ou $REPLY 
done

Exemple de syntaxe:
PS3="Tapez votre choix: "

select i in "Liste" "Ajout" "Modification "Sortie"
do 
	case $REPLY in
	1|2|3) echo $i
	4)     echo $i 	
	       exit 0
	       ;;
	*)     echo "Choix impossible"
	       ;;
	esac 			
done


Résultat d'une exécution:
$ menu.ksh 
1)	Liste 
2)	Ajout 
3)	Modification 
4)	Sortie 
Entrez votre choix: 1 
Liste 
Entrez votre choix: 3 
Modification 
Entrez votre choix:							(Saisie vide)
1)	Liste 
2)	Ajout 
3)	Modification 
4)	Sortie 
Entrez votre choix: 5 
Choix impossible
Entrez votre choix: 4
Sortie 
$


3.6) Fonctionnalités complémentaires


3.6.1) Les tableaux en Korn-Shell

(Remarque: pas de tableau en bourne shell)
Le Korn-shell permet la manipulation de tableaux unidimensionnels. Un tableau est vu par le shell comme un empilement de variables classiques (chaînes de caractères ASCII) manipulées avec une convention de nommage. Il n'y a aucune réservation préalable en mémoire. L'indice 0 désigne le premier élément du tableau.

• Affectation globale par initialisation d'un tableau (si le tableau existe déjà, il est réinitialisé)
$ set -A tab valeur1 valeur2 valeur3
• Désignation des éléments
$ echo ${tab[2]}: Le troisième élément
valeur3 (les indices commencent à zéro)
$ echo $tab: Le premier élément. $tab ou ${tab[0]} sont valeur1 deux autres notations pour le premier élément
$ echo ${tab[*]}: Tous les éléments
valeur1 valeur2 valeur3
• Affectation d'un élément
$tab[0]=premier
$echo ${tab[*]}
premier valeur2 valeur3
• Nombre d'éléments
echo $#tab[*]
3

Conformément à sa structure d'empilement de variables, on peut affecter n'importe quel élément (éventuellement hors de la plage de départ). Dans ce dernier cas, tous les éléments d'indice intermédiaire n'existent pas, ils ne sont donc pas comptés dans le nombre d'éléments du tableau.
$ tab[100]=dernier
$ echo ${tab[*l}
premier valeur2 valeur3 dernier
$ echo ${#tab[*]}
4

3.6.2) Redirections particulières de l'entrée standard: Script en ligne
_________________________________________________
< _________________________________________________
<<\mot "mot" marquera la fin de l'entrée standard, les caractères spéciaux éventuels ne seront pas interprétés.
_________________________________________________

Exemples:
1) Afficher au terminal du texte et réaliser les expansions de variable et commandes si besoin:
#! /usr/bin/sh 
cat « fin 
Ceci est l'entree standard de la commande 
Type du terminal = $TERM 
Il est $ (date +%H,%M ) 
fin 
exit a 

Résultat d'une exécution
Ceci est l'Entree standard de la commande 
Type du terminal = vt100 
Il est 10,05 

2) Afficher au terminal du texte et NE PAS réaliser les expansions de variables, ni de commandes:
#!/usr/bin/sh 
cat << \fin 
Ceci est l'Entree standard de la commande 
Type du terminal = $TERM 
Il est $(date +%H:%M) 
fin 
exit 0 

Résultat d'une exécution:
Ceci est l'Entree standard de la commande 
Type du terminal = $TERM 
Il est $(date +%H:%M)

3) Envoyer un mail depuis un script:
$ cat prog.ksh 
#!/usr/bin/ksh 
mail $1 -s test « FIN 
Ce mail vous est envoye automatiquement par $0 a $(date) 
Excellente journee a vous ! 
FIN 
exit 0

Exemple d'une exécution:
$ ./prog.ksh contact@societe.com
$

3.6.3) Gestion des Entrées/Sorties Compléments
Les entrées/sorties:
• 0 entrée standard
• 1 sortie standard
• 2 sortie des erreurs standard

A l'intérieur d'un script, la commande exec permet d'ouvrir des fichiers en leur associant des descripteurs.
Les numéros 0, 1et 2 sont déjà attribués aux entrée/sortie standards (entrée, sortie, erreur).
On peut, par exemple, utiliser les notations suivantes:
_________________________________________________
exec n>fichier Ouverture d'un fichier en lecture (descripteur n)
_________________________________________________
exec n>fichier Ouverture d'un fichier en écriture (descripteur n)
_________________________________________________
Par la suite, dans votre programme, une utilisation des redirections Unix en mentionnant le numéro de descripteur permet de lire ( <&n ), notamment avec read, ou d'écrire ( >&n) , notamment avec echo ou printf dans les fichiers correspondants.
C'est en particulier un moyen propre de lire un fichier texte ligne à ligne dans un script.
On dispose également des notations <&- et >&- pour fermer les descripteurs:
_________________________________________________
exec <&- Fermeture du descripteur de fichier n
_________________________________________________
exec >&- Fermeture du descripteur de fichier n
_________________________________________________

Exemple de syntaxe:
#!/usr/bin/sh 
### 
# Ouverture du 1er fichier en lecture 
exec 3< fic1 
# Ouverture du 2eme fichier en Ecriture 
exec 4> fic2 
#Lecture ligne par ligne depuis le 1er fichier 
while read <&3 ligne 
do 
	# Ecriture sur la sortie standard 
	echo $ligne 
	echo "Copier(o/n - lecture vide pour sortir)? \c" 
	# Lecture depuis l'entrée standard 
	read rep 
	if 	test -z "$rep"
	then 
		break 
	fi 
	
	if 	test 	"$rep" = o
	then
		# Ecriture dans le 2eme fichier
		echo $ligne >&4
	fi
done
exit 0


Exemple de syntaxe dans le cas particulier des commandes internes reaci/print du Korn-Shell:
Les commandes read et print sont intégrées au Korn-Shell et possèdent une option -u permettant de préciser le descripteur à traiter.
#!/usr/bin/ksh 
# Ouverture du 1er fichier en lecture 
exec 3< fic1 
# Ouverture du 2eme fichier en ecriture 
exec 4> fic2 
# Lecture ligne par ligne depuis le 1er fichier
while 	read -u3 ligne
do 
	#Ecriture sur la sortie standard 
	print $ligne 
	print "Copier(o/n - lecture vide pour sortir)? \c" 
	#Lecture depuis l'entrée standard
	read rep
	if	test	-z "$rep"
	then
		break
	fi
	if	test "$rep" = o
	then
		# Ecriture dans le 2eme fichier
		print -u4 $ligne
	fi
done

3.6.4) La variable IFS
La variable système IFS indique quel est le séparateur de champs lors des lectures (read) et des résultats de substitutions de commande ou de paramètres.
Sa valeur par défaut est "un blanc": Espace, Tabulation et Saut de ligne.
Exemple:
IFS=:
for	i in  $PATH
do 
	echo $i 
done

Note: Le shell utilise aussi cette variable lors de l'évaluation de la ligne de commande: le caractère défini par IFS est remplacé par un blanc avant le lancement de la commande. En particulier, la commande echo $IFS n'est pas un bon moyen de connaître la valeur de IFS!

3.6.5) L'opérateur shift
Cet opérateur permet de parcourir la liste des paramètres en renommant ceux-ci à partir du deuxième. ($1 disparaît, $2 devient $1, $3 devient $2 etc ...)
Bien entendu, le nombre de paramètres $# est décrémenté et la liste $* est mise à jour.
En Bourne-shell, on ne peut désigner que 9 paramètres à la fois, la notation $10 n'existe pas.
En Korn-shell, cette limitation est levée via des notations telles que ${10}.
Concrètement, l'opérateur shift peut servir dans les commandes à options pour se positionner, après traitement syntaxique de ces dites options, au début de la liste des véritables arguments.

Note: Il est possible de décaler plusieurs arguments à la fois: shift n
Exemple:

#!/usr/bin/sh 
#Exemples d'utilisation de shift pour afficher le premier 
#argument et le dernier 

echo "premier: $1"
shift $#-1 
echo "dernier $1"


3.6.6) L'opérateur set
Cet opérateur présente de multiples facettes à usages plus ou moins fréquents.
Les possibilités les plus utiles sont les suivantes:
• Sans arguments, il donne la liste de toutes les variables définies.
• Avec des arguments, l'opérateur permet de repositionner un nouvel ensemble de paramètres ($1, $2 ...).
Exemple:
$ set un deux trois 
$ echo $* 
un deux trois

$ who -r 
.run-level 2 Jun 21 14:10 2 0 S 
$ set 'who -r' 
$ echo $5 $4 $6 
21 Jun 14:10 

Note: Avec deux signes moins (--), l'opérateur set permet, en une seule commande, de libérer tous les paramètres de position
$set --
$ echo $*
kSh: *: parameter not set
$

• Avec des options, il permet différents paramétrages du shell. Les options peuvent être abrégées (voir détail ci-dessous).
Option Description
set -o option Active l'option
set +o option Désactive l'option
set -o Affiche les options et leur état respectif

Quelques options possibles:
allexport ( -a ) Exportation systématique de toute variable du shell
errexit ( -e ) Sortie du shell sur toute erreur
ignoreeof Sortie du shell par exit (pas de "Ctrl-d")
monitor Avertissement lors de fin de tâche
noclobber Pas d'écrasement via les redirections (on doit forcer par >|)
noexec ( -n ) Analyse mais n'exécute pas (pour chercher des erreurs de syntaxe)
noglob ( -f ) Pas de traitement des caractères spéciaux
nounset ( -u ) Génération d'une erreur sur tentative d'acces à une variable non existante
verbose ( -v ) Mode trace (pour chercher les erreurs)
vi Mode de rappel et edition de commandes avec vi
xtrace ( -x ) Autre mode trace sans expansion des variables
etc...
Exemples:
$ set -o
Current option settings
...
noclobber 	off
...
$ set -o noclobber
$ set -o 
Current option settings
...
noclobber 	on
...
$ ls la / > liste
$ ls ial /usr > liste
ksh: /tmp/liste: file already exists
$ ls ial /usr >1 liste 
$ set +o noclobber
$ set -o
Current option settings
...
noclobber 	off
...
$

3.6.7) Gestion des signaux

Exécuter une action lorsque se produit un certain événement.
Syntaxe:
trap 'action' evenement

L'action exécutée peut être soit:
• Une liste de commandes
• Une commande vide " (pour ignorer un événement)
Note: Le signe - (moins ou action non mentionnée) rétablit le comportement par défaut.
L'évènement déclenché peut être soit:
• Un nom de signal
• Un numéro de signal
Par exemple:
Signal Nom Description
2 INTR Interruption clavier
3 QUIT Interruption clavier (Ctrl \) générant un fichier "core"
15 TERM Commande : "kill PID" (sauf kill -9 qui ne peut pas être intercepté)
0 EXIT Déconnexion (fin du shell)
numéro ERR Erreur retournée par une commande

Exemples:
fictemp=/tmp/fic$$
trap 'rm -f $fictemp; exit 1' INTR
 
trap '' 2 3

trap - 2 3
 
trap '$HOME/.logout' EXIT


3.6.8) Autres commandes internes
• eval : évaluation • whence : chemin d'accés Autres commandes internes : - deux-points: commande vide • • typeset: typer les variables
• print: affichage
• printf: affichage formaté
• eval: évaluation (permet d'évaluer une commande avant son exécution, par exemple si une variable contient une commande)
• whence: chemin d'accès (sur toutes les plateformes)
•: (deux points) Commande vide retournant toujours 0 ( permet notamment de constituer des boucles infinies)
• typeset Affecter des attributs à des variables
Option Description -u Transformation des minuscules en MAJUSCULES
-l Transformation des MAJUSCULES en minuscules
-r Lecture seulement (variable non modifiable)
-i Type entier (integer est un alias sur typeset -i)
etc ... 1$ t ype se t -0 $ echo $var ABCD $ var=abcd • print et printf: La commande "print" veut mettre fin aux diverses variantes de la commande echo. Elle accepte les caractères conventionnels suivants:
\a Signal sonore \n Saut de ligne \b Retour arrière \c Pas de saut de ligne \r Retour chariot \t Tabulation \f Effacement d'écran ou saut de page \v Tabulation verticale La commande print intégrée au Korn-Shell possède une option -u permettant de préciser le descripteur à traiter. L'option -u2 permet d'écrire sur l'erreur standard:
$ 'print -u2 "Ceci est un message d'erreur" Ceci est un message d'erreur $ La commande "printf" est très similaire à la fonction de même nom du langage C et permet de réaliser des sorties formatées. Par exemple : $ printf "Nom %-155, Prenom %-155\n" "Jean" "Dupont" Nom : Jean Prenom Dupont $ Formats courants : Forrnat Exemple Description %d %3d 3 chiffres (digit), cadré à droite. %s %-10s Chaine de caractère (string), cadré à gauche. %f %2.3f Nombre réel, arrondi à trois chiffres après la virgule, cadré à gauche.
%d %3d 3 chiffres (digit), cadré à gauche. Note: Penser à placer un \n (saut de ligne) à la fin de la chaîne de caractère à afficher.

• eval - Le shell étend les arguments de "eval" en les séparant par un espace puis traite la chaîne résultat comme une commande.
Cette double évaluation est utile lorsque les arguments de "eval" contiennent des symboles de redirection ou des substitutions de variables.
Quelques exemples:
$ var=toto toto=lOO $ print \$$var $toto $ eval print \$$var 100 $ cat essai #!/usr/bin/sh print IlLe dernier argument est \$$#11 eval print ltLe dernier argument est \$$#11 exit 0 Lancement du script essai:
$ essai a b e d Le dernier argument est $4 Le dernier argument est d $ Créer une variable uid avec la valeur de l'UID du login en cours:
$ id uid=sOl(stagel) gid=sOO(stage) $ eval 'id 1 eut d' (' fl' $ eeho $uid 501 • whence [ -V ] commande La commande whence trouve le chemin d'accès à la commande. Avec l'option -v, la commande whence signale s'il s'agit d'un alias ou d'une commande interne.
Exemples $ whence ps /usr/bin/ps $ whence -v ps ps is /usr/bin/ps $ $ whenee eeho eeho $ whenee -v eeho echo is a shell builtin $ $ whenee l /usr/bin/ls -al $ whenee -v l l is an alias for /usr/bin/ls -al $ • wai t [ n 1 %n ] Attendre la fin d'un processus lancé en arrière-plan Le nombre n indique le PID du processus concerné, %n le numéro de job Sans arguments, la commande wai t attend la fin de tous les pro cess us- fils. Exemple Attendre la fin du processus de PID 11902 [1] 11902 ~ wa1t 11902 Attendre la fin du premier processus lancé en arrière plan: job %1 $ sleep 20 & [1] 11904 $ sleep 30 & [2] 11905 $ wait %1

3.7) Fonctions


3.7.1) Principe et propriétés

Une fonction est un sous-programme qui peut être appelé de la même manière qu'un commande depuis le programme principal.
Syntaxe:
function nom
{
........
}

NB : l' "ancienne syntaxe" compatible Bourne-shell est aussi possible:
nom ()
{
........
}

Pour pouvoir être appelée par un script, une fonction doit être disponible dans le shell interpréteur du script. Pour cela, le moyen le plus simple consiste à écrire la fonction dans le même fichier que le programme appelant. Nous verrons par la suite des solutions permettant de partager des fonctions entre programmes.
Les fonctions peuvent:
• Recevoir des arguments (qui seront traités comme des paramètres de position),
• Modifier un argument reçu,
• Retourner une valeur via l'instruction "return n" (qui positionnera $? à la valeur de n),
• Utiliser des variables locales définies via l'instruction "typeset".

3.7.2) Transmission d'arguments
Le programme appelant la fonction peut lui fournir des arguments. Ils seront récupérés par les variables $1, $2, $3 qui deviennent donc locales à la fonction rendant les arguments passés au programme inaccessibles.
Exemple:
 
#!/usr/bin/ksh 
function f 
{ 
echo $1 $2 
} 
echo bonjour
f marseille paris
exit 0
Exécution:
$prog.ksh
bonjour
marseille paris

Remarque:
Il faut dans un script sourcer le fichier qui contient les fonctions:
#!/bin/sh
...
...
. fonction.lib #fichier contenant les fonctions, ce fichier n'a pas besoin des droits d'exécution.

3.7.3) Modification d'un argument reçu
Il est possible d'utiliser une chaîne de caractères transmise en argument pour créer ou modifier une variable. Ce mécanisme repose sur le fait que les variables shell sont globales par défaut (visibles et modifiables par tous les sous- programmes)
Exemple:
#!/usr/bin/ksh 
function f 
{ 
echo "debut de l'execution de la fonction" 
echo "saisir la valeur de $1 : \c"
read $1
echo "fin de l'execution de la fonction"
}
echo bonjour
f var
echo "valeur de var dans le programme principal:$var"
Exécution:
 
$./prog.ksh 
bonjour 
debut de l'execution de la fonction 
saisir la valeur de var : 1250 
fin de l'execution de la fonction 
valeur de var dans le programme principal : 1250
$

3.7.4) Envoi d'un code retour avec return

L'instruction return pour la fonction joue exactement le rôle de exit pour le programme principal, c'est à dire:
• elle interrompt l'exécution de la fonction et revient au programme principal;
• elle donne aussi la possibilité d'envoyer une valeur qui sera le code retour de l'exécution de la fonction (cette valeur sera donc mise dans la variable $?)
Exemple:
#!/usr/bin/ksh
function f
{
if [ $# = 0 ] ; then
	echo "pas d'arguments pour f" ; return 1
fi
...
}
echo bonjour
f
echo "code retour de f : $?" ; echo fin
Exécution:
 
$ proc.ksh 
bonjour
pas d'arguments pour f
code retour de f : 1
fin
$

3.7.5) Utilisation de variables locales

Par défaut, les variables shell sont globales. Afin de disposer de variables de travail dont la portée est restreinte à la fonction, il est possible de définir des variables locales avec l'instruction typeset.
Note: L'éventuelle valeur initiale de la variable est sauvegardée et restaurée au retour dans le programme principal.
Exemple:
 
#!/usr/bin/ksh 
function f 
{
typeset var=marseille
echo "valeur de var dans f $var" 
} 
echo bonjour
var=paris
f
echo "valeur de var dans proc : $var"
echo fin
exit 0
Exécution:
$proc.ksh 
bonjour
valeur de var dans f : marseille
valeur de var dans proe : paris
fin
$

3.7.6) Partage de fonctions

Il est possible de partager des fonctions entre différents programmes shell, suivant 2 modes : statique ou dynamique
Partage statique
Le principe est de rendre la fonction disponible dans le shell interpréteur du nouveau programme, en forcant son chargement. Cette opération est réalisée à l'aide de l'opérateur . (point).
L'inconvénient principal de cette méthode est le possible chargement dans le shell interpréteur de fonctions inutiles.
Exemple:
$ cat /var/fonctions/lib.ksh 
#!/usr/bin/ksh 
function f
{
	echo "Bienvenue dans f !" 
} 

Utilisation :
$ cat prog.ksh 
#!/usr/bin/ksh 
. /var/fonctions/lib.ksh 
echo "appel de f : "
f 
echo fin

Exécution:
$ prog.ksh 
Appel de f:
Bienvenue dans f !
fin


Partage dynamique en Korn-shell
Plus performante, cette méthode consiste à provoquer le chargement de la fonction uniquement lors de son premier appel. Par la suite, la fonction reste chargée en mémoire.
Mise en oeuvre:
1. Définition d'un fichier $ENV dans le fichier .profile (en général, .kshrc);
2. Création d'un fichier de même nom que la fonction contenant le code de la fonction;
3. dans $ENV, définir la variable FPATH donnant le chemin du fichier de la fonction à partager ET appeler l'instruction autoload sur la fonction;
4. dans tous les scripts appelant la fonction, forcer l'exécution dans le shell courant du $ENV.

La commande typeset - fu permet de lister les fonction" autochargées" dans le shell courant.
Exemple:
$ cat $HOME/$ENV
...
FPATH=/var/fonctions_autoload
autoload f
...
$ cat /var/fonctions_autoload/f
function f
{
echo "Bienvenue dans f !"
}
$ 
Utilisation:
$ cat prog.ksh
#!/usr/bin/ksh
. $ENV
echo "appel de f:"
f
echo fin
Exécution:
$ prog.ksh
appel de f:
Bienvenue dans f!
fin
$


Chapitre 4: Utilitaire et commandes Unix

Objectifs:
• Utilisation des utilitaires standards
• Rappel de certaines licences liées aux utilitaires disponibles optionnellement

4.1) Les différentes licences


Les différentes licences
• GNU GPL
• LGPL
• Logiciels gratuits graticiels

4.1.1) La licence publique générale GNU

La licence publique générale GNU (ou GNU General Public License son seul nom officiel en anglais, communément abrégé GNU GPL voire simplement couramment "GPL") est une licence qui fixe les conditions légales de distribution des logiciels libres du projet GNU. Richard Stallman et Eben Moglen, deux des grands acteurs de la Free Software Foundation, en furent les premiers rédacteurs.
Elle a depuis été adoptée, en tant que document définissant le mode d'utilisation, donc d'usage et de diffusion, par de nombreux auteurs de logiciels libres. La principale caractéristique de la GPL est le copyleft, littéralement copie laissée (pour "droits abandonnés" , jeux de mot anglais entre right (droite) et left (gauche)), qui consiste à détourner le principe du copyright (ou droit d'auteur) pour préserver la liberté d'utiliser, d'étudier, de modifier et de diffuser le logiciel et ses versions dérivées.
La GPL est la licence de logiciel libre la plus utilisée. En avril 2004, 74,6% des 23 479 projets libres présents sur le site Freshmeat et 68.5% des 52 183 projets libres présents sur SourceForge étaient publiés sous licence GPL.

La GNU GPL a une licence soeur, la LGPL (GNU Lesser General Public License et plus anciennement GNU Library General Public License), une version modifiée pour être moins contraignante quant son utilisation dans un contexte de cohabitation avec des logiciels propriétaires. Elle a une autre licence soeur, la GFDL (GNU Free Documentation License) qui, elle, est applicable aux manuels, livres ou autres documents écrits. Cette dernière présente toutefois des inconvénients, mis en avant par le projet Debian; on peut choisir à sa place la GPL, qui est tout fait applicable à un livre, article de carnet Web ou autre création.

4.1.2) Logiciels gratuits: graticiels

Un graticiel (freeware) est un logiciel mis gratuitement à disposition par son créateur soit en tant que logiciel libre, soit en tant que logiciel propriétaire, auquel cas il est soumis à certaines contraintes quant à sa diffusion. Les graticiels ne doivent pas être confondus avec les logiciels commerciaux diffusés de manière bridée en termes de fonctionnalités (dit de démonstration), ou en termes de durée d'utilisation (partagiciel, shareware en anglais). Ils sont parfois financés par la publicité qu'ils contiennent.

4.2) Filtres et utilitaires


Filtres et utilitaires:
• head et tail
• wc
• cut
• tee
• sort

Les filtres sont des utilitaires standards, présents sur tous les systèmes Unix.
Ils permettent de multiples traitements sur les fichiers de texte (organisés en lignes) et constituent des outils très intéressants, aussi bien pour le développeur que pour l'utilisateur.
Leur appellation provient du fait qu'ils apparaissent assez souvent dans des "pipelines" pour mettre en forme des résultats de commandes.
Ces résultats sont écrits sur la sortie standard. On utilise des redirections pour les archiver dans des fichiers.

4.3) Quelques filtres simples


4.3.1) La commande head

La commande head affiche les premières lignes d'un fichier.
head [-n] [fichier] avec -n le nombre de lignes souhaitées (par défaut 10).
Remarque: on peut aussi demander à afficher les lignes 2 à n, dans ce cas utiliser tail -n+2 fichier

4.3.2) La commande tail

La commande tail permet d'afficher les dernières lignes d'un fichier.
tail [ +/-[n] [l|b|c] ] [-f] [fichier]
+n Affichage à partir de la ligne de numéro n
-n Affichage des n dernières lignes (défaut 10)
l n est exprimé en lignes (défaut)
b n est exprimé en blocs de 512 octets
c n est exprimé en caractères
f Attente de nouvelles lignes (sortie par BREAK)

4.3.3) La commande wc (word count)

La commande wc permet de compter les lignes, mots et caractères d'un fichier.
wc [ -lwc ] fichier
-l nombre de lignes.
-w nombre de mots.
-c nombre de caractères.

4.3.4) La commande cut

La commande cut permet de sélectionner des caractères ou des mots dans une ligne.
cut -fliste [-dsep] [-s] [fichier ... ]
cut -cliste [fichier ... ]
liste n-m ou n,m ou -m (à partir du début de ligne) ou m- (jusqu'à la fin de la ligne)
-c Sélection de caractères
-f Sélection de mots
-dsep Redéfinition du séparateur
-s Suppression des lignes sans séparateurs

4.3.5 La commande tee
La commande tee permet de mémoriser les résultats intermédiaires dans le fichier donné en argument. Par exemple mémoriser la sortie standard permet de stocker le résultat et le voir à l'écran).
tee [-a] fichier
-a permet une utilisation en mode" ajout"

Quelques exemples:
$ls -la | tail +2
Liste de tous les fichiers du répertoire de travail en éliminant la première ligne.

$ head -15 exemple | tail +10
Affichage des lignes 10 à 15 du fichier exemple

$ ls | wc -1
Afficher le nombre de fichiers du répertoire courant

$ ls | wc -l | tee liste 
Afficher le nombre de fichiers du répertoire courant et le mémoriser dans le fichier liste

$wc -lc exemple
Nombre de mots et lignes du fichier exemple

$cut -d: -f 1,3,6,7 /etc/passwd
Sélection des champs nom, UID, répertoire de connexion et shell de connexion du fichier administratif /etc/passwd.

$cut -c1-9,64- exemple
Sélection de l'intervalle de colonnes "1 à 9" et "64 à fin de ligne" du fichier exemple.

4.3.6) Utilitaire de tri: sort

sort [options] [ -k keydef] [ -o fichier] [ - tcar ] fichiers ...
• L'unité de traitement est la ligne ou le mot ( champ ).
• Le critère de tri par défaut est l'ordre ascii.
• De multiples options permettent de choisir des critères plus réalistes (alphabétique, numérique ... ).
Si aucun fichier n'est donné en argument ou si on utilise le caractère - (signe moins), la commande traite son entrée standard.
Le résultat du tri est écrit sur la sortie standard.

Quelques options:
-b Pour une bonne gestion du nombre variable d'espaces ou de tabulations entre les champs (option quasiment indispensable pour des tris alphabétiques)
-d Seuls les lettres, chiffres, espaces et tabulations sont significatifs pour le tri
-f Minuscules et MAJUSCULES sont confondues
-n Tri numérique (pour trier en fonction de la tailel du fichier)
-r Résultat en ordre décroissant
-u Suppression de lignes multiples dans le résultat
-o fichier Sauvegarde du résultat dans le fichier spécifié (Ce fichier peut être un des fichiers d'entrée)
-tcar Redéfinition du caractère séparateur

4.3.7) Utilisation des champs

La notation -k keydef permet d'indiquer que le tri doit s'effectuer uniquement sur certains champs de la ligne.
Il est possible d'indiquer plusieurs couples de clés pour opérer un tri à plusieurs passes.
Ces clés s'expriment sous la forme [ début [type] [,fin [type]]
début ,fin Portion de ligne à traiter en indiquant les Numéros du champ
type Une ou plusieurs options parmi b, d, f, i, n ou r. Le type b, s'il est positionné, s'applique sur le champ souhaité en plus de l'option b.

Quelques exemples:
$ sort -k2,2 fic
Tri (critère Ascii) sur le deuxième champ du fichier fic.

$ sort -bf -k2,2 fic
Tri alphabétique sur le deuxième champ.
Ignorer le nombre d'espaces avant et après le champ.
$ sort -t: -rn -o fichier.out -k3,3 fic
Tri (critère numérique, ordre décroissant) sur le troisième champ avec redéfinition du séparateur de champs.
Sauvegarde du résultat dans le fichier fichier.out.

4.4) Transformations de caractères: tr


tr [options] [ chaînel [ chaîne2 ] ]
Ce filtre lit l'entrée standard pour effectuer des substitutions ou des suppressions de caractères. Les résultats sont écrits sur la sortie standard.
Dans la syntaxe de base, les caractères mentionnés dans "chaîne1" sont remplacés par ceux de même position dans "chaîne2".
Des abréviations sont possibles pour désigner des ensembles de caractères:
Notation Description
[a- z] Les lettres minuscules (intervalle)
[a*n] n fois le caractère a (* seul signifie "un nombre quelconque")
\xyz Code Ascii en octal du caractère
[ :class: ] Indique une classe de caractères :lower: :upper: :alpha: :alnum: :digit: :space :
On peut utiliser les options suivantes:
Notation Description
-d Supprimer les caractères apparaissant dans "chaine1"
-s Les caractères consécutifs identiques sont réduits à un seul exemplaire
-c Négation -> Les caractères n'apparaissant pas dans "chaine1"

Quelques exemples:
$ tr "[a-z]" "[A-Z]" < fichier
Transformer les minuscules en MAJUSCULES.

$ tr "[: lower:]" "[ :upper:]" Idem en utilisant les classes de caractères.

$ tr -d "abcd" < fichier
Les caractères a, b, c et d sont supprimés.

$ tr -sc" [A-Z] [a-z]" "[\012*]" Les caractères non alphabétiques sont transformés en un saut de ligne. Les sauts de ligne consécutifs sont éliminés. On obtient un mot alphabétique par ligne.


4.5) Rappel sur les expressions régulières


Expressions régulières et grep

• Ensemble de caractères spéciaux
• Utilisation de grep

Les expressions régulières forment un langage de description d'ensembles de chaînes de caractères.
Parmi les différents utilitaires UNIX utilisant la notion d'expressions régulières, citons ex (appelé depuis le mode de commandes syntaxique de vi ), les filtres awk/nawk, grep, sed.
Voici une liste des caractères spéciaux les plus employés dans les expressions régulières:
Caractère Description
^ Début de ligne
$ Fin de ligne
. Présence d'un caractère quelconque
[caractères] Un caractère parmi un ensemble donné
[^caractères] Un caractère ne figurant pas dans l'ensemble
* Un nombre quelconque d'apparitions d'un caractère (éventuellement aucune apparition)
\ Annuler la sémantique d'un caractère dans l'expression


Les expressions régulières enrichies introduisent des caractères supplémentaires:
Caractère Description
+ Début de ligne
? Fin de ligne
() Présence d'un caractère quelconque
| Un caractère parmi un ensemble donné
Note: Certaines expressions régulières enrichies ne sont pas utilisables avec sed et awk. Elles sont accessibles avec le grep conforme à la norme XPG4. Quelques exemples à déchiffrer:
Caractère Description
^[abc] a b ou c en début de ligne
^[^abc] tout caractère sauf a b et c en début de chaîne.
^[^^]) tout caractère autre que ` en début de chaîne.
ab?c ac ou abc.
(ab)+c abc ou ababc ou abababc etc.
^ab|cde *$ ab en début de chaîne ou cde suivi d'espaces éventuels en fin de chaîne.
^[0-9] +$ chaîne constituée uniquement de chiffres.

4.6) Recherche d'expressions avec grep

Ce filtre permet de rechercher des expressions littérales ou "régulières" dans des fichiers. Les lignes comportant les expressions recherchées sont affichées sur la sortie standard.
Le filtre grep présenté ici est celui conforme au guide XPG4. Sur de nombreuses versions d'UNIX, le grep par défaut est une ancienne version qui ne sait pas utiliser les expressions régulières enrichies.
Syntaxe:
grep [-E -F] [-c J -1 J -q] [options] expr fichiers ... ou
grep [-E -F] [-cJ-1J-q] [options] [ -e expr ... ] [ -f fichier ... ] fichiers .. Quelques Options:
-E L'expression est traitée comme expression régulière enrichie (anciennement egrep).
-F L'expression est traitée comme expression littérale (anciennement fgrep).
-c Afficher le nombre de lignes trouvées
-l Afficher uniquement les noms des fichiers
-q Supprime l'affichage des lignes résultat
-i MAJUSCULES et minuscules sont confondues
-n Chaque ligne est précédée de son numéro dans le fichier
-v Les lignes ne comportant pas l'expression
-x Les lignes exactement identiques à l'expression
-e expr Permet de chercher plusieurs expressions. Permet aussi de chercher une expression commenant par - (signe moins)
-f fichier Les expressions cherchées sont décrites dans un fichier (une par ligne)

Notations fréquentes et utiles:
^$ Ligne vide (un début et une fin).
. Ligne non vide.
.* "Reste de la ligne" ou "ligne complète" suivant le contexte.


Quelques exemples:
$ grep '^abc' fichier
Lignes commençant par la chaîne "abc"

$ grep -E '^abc' fichier
Idem

$ grep -F '^abc' fichier
Lignes contenant la chaîne "abc"

$ grep '^[abc]' fichier
Lignes commençant par a ou b ou c

$ grep '^[0-9]' fichier
Lignes ne commençant pas par un chiffre

$ grep 'abc.$' fichier
Lignes se terminant par la chaîne "abc" suivie d'un caractère quelconque

$ grep -E '^[O-9]+$' fichier
Lignes constituées d'au moins un chiffre et uniquement de chiffres.

$ grep -n '^' fichier
Numéroter toutes les lignes (toutes les lignes ont un début)

$ grep -f motifs fichier
Recherche des expressions régulières indiquées dans le fichier "motifs"

$ grep -i 'expr *$' fichier
Lignes se terminant par la chaîne "expr" (minuscules ou majuscules) suivie d'un nombre quelconque d'espaces

$ grep -e '^abc' -e 'ef *$' fichier
Lignes commençant par la chaîne "abc" ou bien se terminant par la chaîne "ef" suivie d'un nombre quelconque d'espaces

$ grep -E '^abc|ef *$' fichier
Idem

4.7) La commande getopts


La commande getopts • Analyse des options • Un format" Unix"
L'un des problèmes lors de l'écriture d'un script est l'analyse syntaxique des options pouvant être passées à un programme. Il faut tenir compte des différentes possibilités d'utilisation du script (par exemple -ab, -ba, -b -a etc.).
La comande getopts vous facilite le travail. Vous lui dites quelles sont les options, y compris celles qui ont des arguments. Elle fait pour vous l'analyse syntaxique et permet à l'utilisateur d'indiquer ces options avec la même souplesse que dans les commandes de base.
La syntaxe de base est la suivante :
getopts [:]lettre[:] ... VARIABLE [ARGUMENTS ... ]
• Le symbole : qui peut précéder les lettres indique que vous gérez vous même le cas des options incorrectes.
La commande procède sinon un traitement par défaut.
• Chaque lettre désigne l'une des options autorisées dans la ligne de commande sous la forme -lettre.
• Le symbole: qui peut suivre une lettre signifie que l'option attend un argument. Cet argument sera dans la variable pré définie OPTARG. • VARIABLE désigne la variable dans laquelle getops met l'option rencontrée votre disposition.
• ARGUMENTS désigne la chaîne des arguments, $* par défaut.

getopts renvoie 0 (vrai) pour signifier qu'elle a trouvé une option. On utilise donc getopts en conjonction avec une boucle while ou un case.
Voici un exemple d'utilisation de getopts.
#!/bin/ksh 
# 
# Exemple d'utilisation de getopts 
# 
# ./getoptsl.ksh -avf fichier 
# 
# 
# -a : Option a 
# -v : Option v 
# -f fichier : Option f avec un fichier en argument 
# 
# 
flaga=O 
flagv=O 
flagf=O

while getopts af:v option
do 
	case $option in 
		a) flaga=1 ;; 
		f) flagf=1 
			fichier=$OPTARG
			;; 
		v) flagv=1 ;; 
	esac 
done 
if [ $flaga -eq 1 ]
then 
    echo "Option a activee." 
fi

if [ $flagv -eq 1 ] 
then 
    echo "Option v activee."
fi

if [ $flagf -eq 1 ]
then
    echo "Option f activee. Operation sur le fichier $fichier" 
fi

exit 0


$ ./getoptsl.ksh -avf fichier1
Option a activee.
Option v activee.
Option f activee. Operation sur le fichier fichier1



Chapitre 5: sed & awk

Objectifs:
• Utilisation de awk et de nawk
• Utilisation de sed

5.1) Edition (non interactive) de fichiers: sed

Utilisation de sed:
• Edition non-intéractive.
• Utilise les mêmes commandes que vi.

Ce filtre est un éditeur non interactif qui copie les fichiers d'entrée sur la sortie standard après leur avoir appliqué un certain nombre de commandes.
Syntaxe:
	sed 	[-n] 	'commandes_sed' 	fichiers ... 
ou 
	sed 	[-n] 	-f fichier_commandes 	fichiers ...

5.1.1) Syntaxe des commandes sed et principe de fonctionnement
[ adresse1[,adresse2] ] action [arguments]
Les crochets indiquent un aspect facultatif et n'apparaissent pas dans les commandes.
Tous ces éléments ne sont séparés par aucun espace.
En l'absence d'adresses de sélection, l'action a lieu sur toutes les lignes des fichiers en entrée.
L'action par défaut est d'afficher la ligne sur la sortie standard.
L'option -n permet de supprimer cette sortie systématique des lignes.
Une adresse peut être:
• Un numéro de ligne
• Le caractère $ désignant la dernière ligne
• Une expression littérale ou régulière entre deux caractères /

Quelques actions usuelles:
d: Ne pas afficher la ligne.
p: Afficher la ligne (s'utilise souvent avec l'option -n).
q: Abandonner le traitement.
s/expr1/expr2/: Remplacer la première expression par la seconde..une seule fois par ligne.
s/expr1/expr2/g: Remplacer la première expression par la seconde..plusieurs fois par ligne si nécessaire.
s/exprl//: Supprimer l'expression.
s/exprl/...&.../: Expanser la première expression (elle-même + "quelque chose").( La notation & signifie "reprendre la première expression").
=: Afficher le numéro de ligne.

Remarque:
Pour écraser un fichier fic après avoir appliqué des commandes, on est obligé de faire ceci:
sed -f fichier_commandes fic>tmp
mv tmp > fic

Quelques exemples:
$ sed 's/monsieur/madame/g' fichier Remplacer une chaîne par une autre plusieurs fois par ligne
$ sed 's/^/ /' fichier Décaler le début de chaque ligne d'une espace.
$ sed '/./s/^/' fichier Idem uniquement sur les lignes non vides
$ sed -n '/expression/!p' fichier Afficher les lignes ne contenant pas l'expression ( Le! indique la négation de l'expression)
$ sed -n '20,30p' fichier Afficher les lignes de numéro 20 à 30
$ sed '1,10d' fichier Ne pas afficher les 10 premières lignes
$ sed -n '/./p' fichier Afficher uniquement les lignes non vides
$ sed '/^$/d' fichier Même traitement
$ sed '/expression/q' fichier Afficher jusqu'à trouver une expression donnée
$ sed -n '/expression/=' fichier Afficher les numéros des lignes contenant une expression donnée.
$ sed 's/[0-9] [0-9] */(&)/g' fichier Mettre entre parenthèses les nombres entiers plusieurs fois par ligne si nécessaire

Remarque: g pour le faire plusieurs fois.

5.2) Introduction au langage awk

Cet utilitaire awk tire son nom de ceux de ses concepteurs (Alfred AHO, Peter WEINBERGER, Brian KERNIGHAN qui est aussi l'inventeur du langage C).
C'est un outil très adapté pour réaliser des tâches de manipulation de données sans avoir à les programmer dans un langage classique comme le C.
En effet, beaucoup de choses sont implicitement résolues (les entrées, la gestion des "champs", la gestion mémoire, les déclarations, les initialisations...).

5.2.1) Syntaxe et principe de fonctionnement
syntaxe:
awk -f fichier commandes fichiers ... ou awk 'liste-de-commandes' fichiers ...
Une commande est constituée ainsi: motif { action }
Le motif sert d'expression de sélection des lignes pour y appliquer l'action associée.
Si le motif est absent, toutes les lignes sont concernées par l'action. L'action par défaut consiste à afficher la ligne.
Chaque ligne d'entrée est automatiquement divisée en champs. Les différents champs sont nommés respectivement: $1 $2 $3 ... $NF
NF représente le nombre de champs de la ligne en cours de traitement.
Le séparateur de champs peut être positionné à un caractère particulier. Pour ce faire, on peut procéder de deux façons:
1) On utilise comme première commande : BEGIN { FS = "caractère" }
ou
2) A l'appel de "awk", on utilise l'option -Fcaractère
D'autres variables intéressantes sont pré définies:
$0 La ligne entière.
NR Numéro de la ligne courante.
FILENAME Nom du fichier courant d'entrée.

5.2.2) Les motifs
Les programmes peuvent souvent se résumer à une suite de motifs puisque l'action par défaut est l'impression des lignes sélectionnées.
"awk" est donc un outil très puissant de sélection.
Quelques motifs possibles:
- Expression bâtie avec des opérateurs très proches de ceux du langage C:
$3 < 10
$3 < $2 + 10 && $4 == "dupont"
- Expression littérale ou régulière entre deux caractères / :
/dupont/
/^[0-9]/
- Intervalle de numéros de lignes
NR == 10 , NR == 15
- Le motif BEGIN
L'action associée est exécutée avant le traitement des fichiers d'entrée
- Le motif END
L'action associée est exécutée après le traitement des fichiers d'entrée

5.2.3) Les actions
Une action est une suite d'instructions. Chaque instruction est terminée par un; ( point-virgule) ou un saut de ligne. Instructions disponibles • Les fonctions d'affichage print ( affichage brut) et printf ( affichage formaté ) • Instruction bâtie avec des opérateurs très proches de ceux du langage C • Instructions de contrôle ( tests, boucles, fonctions intégrées ... Quelques exemples : $ awk ' $3 >1000 { print $1 , $2 , $3 } , fichier Pour toutes les lignes où le troisième champ est supérieur à mille, on affiche la valeur des trois premiers champs. $ awk ' { print NR , $0 } , fichier Numéroter les lignes d'un fichier. $ awk ' { printf "%4d %s\n" , NR , $0 } , fichier Même traitement avec formatage. $ awk '$3 > 1000 { va1++ } END { print val }, fichier Afficher le nombre de lignes où le troisième champ est supérieur à 1000. $ awk '$3 > max {max = $3; maxnom = $2 } END { print max , maxnom J' fichier Afficher la valeur maximum du troisième champ ainsi que celle du deuxième champ associé. $ awk ' { noms = noms $2 Il " } END { print noms }, fichier Afficher la concaténation de tous les deuxièmes champs ( Concaténation par juxtaposition) $ awk 'BEGIN { printf "Calcul du maximum et de la moyenne\n"} { somme += $3 } $3 >max { max = $3 } END { printf "Maximum = %lO.2f Moyenne } %lO.2f\n", max, somme/NR , fichier

5.2.4) Les tableaux associatifs
On peut manipuler des tableaux de couples" clé = valeur" ( clé unique). En général, cette clé prend toutes les valeurs possibles d'un des champs du fichier traité. Contenu du fichier" exemple" roger martin 12000 cd1 rene duva1 500 cd1 marie pervenche 12010 cd3 Marcel dupond 600 cd2 paul martin 10000 cd4 roger martin 12500 cd1 Rene DUVAL 510 cd1 marie pervenche 13000 cd3 marie martin 13000 cd3 Sophie Martinez 6512 cd2 Sylvie Martinelli 45678 cd2 Paul Legrand 4560 cd5 michel DUVAL 54500 cd1 Mireille Duvalier 12345 cd2 Paul LEGRAND 14560 cd5 Rene Pervenche 5400 cd3 Paul martinez 5600 cd2 Andre dupond 650 cd5 Soit le fichier prog contenant les instructions suivantes BEGIN {printf "EXEMPLE DE TABLEAU ASSOCIATIF\n" } {tab($2] += $3} {for (nom in tab) printf "%-20s %6d\n" , nom, tab(nom] } END On construit dynamiquement un tableau associatif" tab" dont les indices (clés) sont toutes les valeurs possibles du deuxième champ. Pour une clé donnée, la valeur associée consiste à faire la somme des valeurs du troisième champ. On obtient à l'exécution $ awk -f prog exemple EXEMPLE DE TABLEAU ASSOCIATIF dupond 1250 Legrand 4560 martin 47500 LEGRAND 14560 pervenche 25010 martinez 5600 Pervenche 5400 Duvalier 12345 DUVAL 55010 duval 500 Martinelli 45678 Martinez 6512

5.2.5) Aide-mémoire résumé de awk
Variables prédéfinies Variable Nombre d'arguments de la ligne de commande. Description ARGC ARGV Tableau contenant les arguments de la ligne de commande. FILENAME Numéro d'enregistrement dans le fichier courant. Nom du fichier d'entrée courant. FNR FS Séparateur de champs en entrée (" espace" par défaut). Nombre d'enregistrements lus jusqu'à présent. NF Nombre de champs dans l'enregistrement courant. OFMT NR Format d'affichage pour les nombres ("%. 6g" par défaut). OFS Séparateur de champs à l'affichage ("espace" par défaut). Séparateur d'enregistrements à l'affichage (" \n" par défaut). ORS RLENGTH Longueur de la concordance obtenue par la fonction "match" . RS Séparateur d'enregistrements en entrée (" \n" par défaut). Première position dans la chaîne qui concorde avec la fonction "match". RSTART Opérateurs = += -= *= Affectation. Opérateurs /= %= ,.. Description ? : Ou logique. Si Alors Sinon. Il &:&: ET logique. Opérateurs de comparaison. Concordance ( ou non) avec une expression régulière. < <= > >=! = Multiplication, division, modulo. + - Addition, soustraction. Plus unaire, moins unaire, NON logique. * / % ~ ( ou ** ) Puissance. + -! ++ -- Incrémentation et décrémentation. Instructions de contrôle if ( expression ) instruction if ( expression ) instructionl else instruction2 while ( expression ) instruction for ( expressionl; expression2; expression3 instruction for ( variable in tableau ) instruction do instruction while ( expression ) break continue next exit expression

5.2.6) Quelques fonctions intégrées
Fonction atan2 x, y ) cos X ) exp x ) int x ) log x ) rand ( ) sin ( x ) sqrt x gsub ( r 1 s 1 t ) Description Arctangente Cosinus. Exponentielle. Partie entière. Logarithme. Nombre aléatoire dans l'intervalle [0,1]. Sinus. Racine carrée. Remplace globalement par s chaque occurrence de r dans la chaîne t. ( $ 0 par défaut ). Retourne le nombre de remplacements effectués. index ( s 1 t Première position de t dans s. length ( s ) Longueur de la chaîne. match ( sir Position de la sous-chaîne en concordance avec l'expression r. Mise à jour des variables RSTART et RLENGTH. split ( s 1 t 1 sc ) Décomposition de s en un tableau t selon le séparateur sc. ( FS est le séparateur par défaut ). sub ( r,s 1 t Remplace par s la première occurrence de r dans la chaîne t. substr s 1 i 1 n Sous-chaîne de longueur n de s débutant en position i. system commande) Exécution d'une commande. getline Lecture de données via l'entrée standard, un fichier ou un "pipe". getline getline var getline
Annexe A: Enoncé des exercices

A.1) TP DE PROGRAMMATION SHELL
TP1) Traitement de la ligne de commandes et utilisation de la commande test sur les fichiers
  • Ecrire un script tp1.ksh qui reçoit un fichier en argument
  • Le script vérifie qu'un argument est passé sur la ligne de commandes
  • Si c'est un répertoire, le script liste son contenu avec ls
  • S'il s'agit d'un fichier ordinaire "texte", le script l'affiche en mode paginé avec more

• Appel: $ ./tpl.ksh fichier

TP1-bis) Traitement de la ligne de commandes et utilisation de la commande test sur les fichiers
  • Idem TP1, avec le test en syntaxe Korn Shell
  • Le nom du script est tp1bis.ksh

Appel: $ ./tplbis.ksh fichier

TP2) Exemple de boucle for
Ecrire un script tp2. ksh qui liste dans une boucle for les commandes d'un répertoire donné en argument.
S'il n'y a aucun argument, le script traite le répertoire courant.
Note: Une commande est un fichier ordinaire et exécutable.
Appel: $ ./tp2.ksh [ fichier]

TP2-bis) Exemple de boucle for et d'utilisation des expressions arithmétiques
Idem TP2, avec le comptage du nombre de commandes situées dans le répertoire. Le nom du script est tp2bis.ksh.
Appel: $ ./tp2bis.ksh [ fichier ]

TP3 Exemple de boucle while et de lecture clavier
Ecrire un script tp3.ksh qui affiche un message au terminal à une heure donnée. Il récupère l'heure du système sous la forme hh:mm.
Il réalise la lecture au clavier d'une heure au même format hh:mm.
Il vérifie dans le cas d'une saisie non vide que l'heure est postérieure sinon il quitte le programme.
Dans une boucle while, le script attend cette heure en recalculant l'heure système toutes les 10 secondes pour afficher un message au terminal de l'utilisateur.
Note: Penser à utiliser la commande date avec le format suivant: date +%H :%M
Appel: $ • /tp3.ksh

TP4 Exemple d'aiguillage case

Ecrire un script tp4.ksh qui reçoit deux noms de fichiers fic1 et fic2 en arguments.
Le traitement est une boucle sur la lecture des informations au clavier.
La fin de la boucle a lieu sur saisie vide.
À l'aide de l'aiguillage case, les lignes ne comportant que des lettres sont ajoutées dans le fichier fic1, les lignes ne comportant que des chiffres sont ajoutées dans le fichier fic2. Les autres lignes sont rejetées.
Le script affichera le nombre de lignes pour les trois cas en fin de traitement. Appel: $ ./tp4.ksh fic1 fic2

TP 5 Instruction select , Expressions arithmétiques et tableaux

Ecrire un script tp5.ksh qui réalise une opération sur 2 entiers
Les opérations suivantes sont disponibles: Addition, Soustraction, Division, Multiplication
La structure select du Korn Shell est utilisée pour valider le type d'opération souhaitée, afficher la liste des toutes ces opérations et sortir du script.
Après saisie des 2 entiers, le script vérifie que les nombres sont des entiers et réalise l'opération demandée par l'utilisateur.
Appel: $ ./tp5.ksh

Un plus dans le script est de prévoir l'opération Modulo Appel: $ ./tp5bis.ksh

TP6 Exemple de traitement des interruptions, utilisation des fonctions et de la boucle while
Ecrire un script tp6. ksh qui réalise dans une boucle infinie while la création puis le grossissement d'un fichier par la redirection d'un message dans le fichier.
Le script intercepte les signaux INT, QUIT et TERM comme suit:
  • Ignore le signal QUIT ( 3 )
  • Sur réception du signal INT ( 2 ) ou TERM ( 15), appelle une fonction de déroutement qui supprime le fichier

Appel: $ • /tp6.ksh

A.2 ENONCES D'EXERCICES SUR LES FILTRES
Dans la suite la référence au fichier" exemple" est faite à partir du contenu vu ci-dessous:
roger martin 12000 cd1
rene duva1 500 cd1
marie pervenche 12010 cd3
Marcel dupond 600 cd2
paul martin 10000 cd4
rager martin 12500 cd1
Rene DUVAL 510 cd1
marie pervenche 13000 cd3
marie martin 13000 cd3
Sophie Martinez 6512 cd2
Sylvie Martinelli 45678 cd2
Paul Legrand 4560 cd5
michel DUVAL 54500 cd1
Mireille Duvalier 12345 cd2
Paul LEGRAND 14560 cd5
Rene Pervenche 5400 cd3
Paul martinez 5600 cd2
Andre dupond 650 cd5


Exercice 1 Utilitaire de tri sort sur le fichier exemple
1) Trier sur le troisième champ en ordre décroissant 2) Trier sur le deuxième champ ( minuscules et majuscules confondues) 3) Trier sur le deuxième champ ( minuscules et majuscules confondues) puis deuxième passage sur le premier champ ( même critère) puis troisième passage sur le troisième champ

4) Trier sur les trois premiers caractères du deuxième champ (critère code ascii)

Exercice 2 Utilitaire de tri sort sur des commandes ou fichiers du système

1) Trier le résultat de "ls - al" d'après la taille des fichiers
2) Trier le fichier /etc/passwd d'après le numéro de login (UID) en ordre décroissant
Exercice 3 Transformation de caractères tr en sortie de commande ls

1) Afficher la liste des fichiers du répertoire courant en majuscules
2) Remplacer, dans le résultat de "ls -al", tout caractère n'étant ni un chiffre, ni un espace, ni un saut de ligne par la lettre X.

Exercice 4 Recherche d'expressions avec grep sur le fichier exemple
1) Rechercher les lignes du fichier "exemple" qui commencent par m ou M.
2) Rechercher les lignes du fichier" exemple" qui comportent la lettre a en deuxième position.
3) Rechercher les lignes du fichier" exemple" qui se terminent par 1 ou 2.
4) Rechercher les lignes du fichier" exemple" qui commencent par une majuscule OU qui se terminent par la chaîne "cd1".
5) Rechercher les lignes du fichier" exemple" qui commencent par une majuscule ET qui se terminent par la chaîne "cd2" (avec le résultat trié sur le troisième champ en ordre décroissant ).

Exercice 5 Recherche d'expressions avec grep sur le fichier /etc/passwd
1) Dans le fichier /etc/passwd, rechercher les lignes correspondant aux utilisateurs du Korn-shell.
2) Même question pour les utilisateurs potentiels du Bourne-shell.

Exercice 6 Edition non interactive de fichiers sed sur le fichier exemple
1) Dans les lignes du fichier" exemple" qui ne contiennent pas la chaîne "cd1", remplacer la chaîne "cd" par la chaîne "code".
2) Afficher le fichier "exemple" jusqu'à trouver la chaîne "cd5" (ligne non comprise).
3) Décaler, de quelques espaces, le début des lignes du fichier "exemple" commençant par une majuscule
4) Mettre des parenthèses autour des lignes du fichier "exemple" qui se terminent par "cd1"
5) Idem "question 4" mais en n'affichant que les lignes modifiées, triées sur le deuxième champ (minuscules et majuscules confondues) avec une deuxième passe sur le troisième champ en ordre décroissant
6) Remplacer tous les "0" du fichier exemple par des "x" et tous les "1" par des "y"

Exercice 7 Traîtement sur le fichier exemple avec l'outil awk
1) Afficher le fichier en numérotant les lignes et en permutant les deux premières colonnes.
2) Afficher noms et prénoms des personnes correspondant aux codes "cd1"ou "cd2".

Afficher en final le nombre de ces personnes.
3) Afficher la ligne pour laquelle le nombre (3ème colonne) est le plus grand.
4) Pour chaque code, afficher le total des nombres (3ème colonne).
Afficher en final la moyenne des nombres.


A.3 ENONCES D'EXERCICES DE L'ATELIER DE PROGRAMMATION SHELL

Les ateliers ci-dessous ne sont pas proposés dans un ordre croissant de difficulté. On peut donc les aborder dans un ordre quelconque selon leur thème respectif ou selon ses préférences personnelles.

Atelier 1 Modification de nom de fichiers avec confirmation éventuelle et gestion de la ligne de commandes
Ecrire un script atelier1.ksh qui recoit deux arguments .ext1 et .ext2.
Le but du script est de renommer tous les fichiers d'extension. ext1 du répertoire courant en * . ext2.
Le script vérifiera que les arguments sont des "extensions:" ." suivi de l'extension en minuscules.
Si on donne l'option " -i ", le script propose la confirmation pour chaque fichier.
Note : Penser à utiliser la commande basename sur les noms de fichiers à traiter
Syntaxe: $ basename string [suffix]
Appel: $ atelier1.ksh [ -i ] .ext1 .ext2

Atelier 2 Autre script de modification de nom de fichiers
Ecrire un script atelier2.ksh qui recoit des noms de fichiers en arguments.
Pour chaque argument, s'il s'agit d'un fichier ordinaire dont le nom ne contient que des MAJUSCULES, on le renomme en minuscules.
Appel: $ atelier2.ksh liste_fichiers

Atelier 3 Traitements sur les fichiers : test
Ecrire un script atelier3 .ksh qui recoit des noms de fichiers en arguments.
Si le fichier existe et est un fichier ordinaire, on affiche sa taille.
Si le fichier n'existe pas, on le créée de taille O.
Si l'option "-c" est utilisée, le script ne créée pas le fichier s'il n'existe pas.
Appel: $ atelier3.ksh [ -c ] liste_fichiers

Atelier 4 Menu simple avec case et appel de commandes UNIX
Ecrire un script atelier4. ksh sous la forme d'un menu dans une boucle until. Le script prévoit avec la structure case:
  • 1. L'affichage de l'heure
  • 2. Le changement de répertoire courant
  • 3. La sauvegarde au format tar compressé des fichiers ordinaires du répertoire courant après avoir vérifié qu'il y en a Après saisie du nom de l'archive souhaité, la création de celle-ci se fait sous /tmp
  • 4. La liste du contenu d'une archive dont on saisit le nom
  • 5. La Restauration interactive de fichiers d'une archive
  • 6. 0 La Sortie

Rappel sur la syntaxe de tar:
Création d'une archive: tar -cvf fichier_archive liste_a_sauvegarder Lecture d'une archive: tar -tvf fichier_archive Imore Restauration d'une archive: tar -xvf fichier_archive liste_a_restaurer Appel: $ atelier4.ksh

Atelier 5 Gestion de la ligne de commande et traitement sur les fichiers
Ecrire un script atelier5.ksh qui reçoit en premier argument un entier puis une liste de fichiers.
Le script vérifie que le premier argument est un entier.
Il affiche pour chaque fichier les lignes plus longues que cette valeur et le nombre de lignes.
Appel: $ atelier5.ksh valeur liste_fichiers

Atelier 6 Traitements sur les fichiers et Expressions arithmétiques Ecrire un script atelier6. ksh qui reçoit une liste de noms de fichiers en arguments.
Le script ne conserve de la liste d'arguments que les fichiers ordinaires et affiche la taille en octets de chacun, la taille totale ainsi que le nom du plus gros fichier.

Appel: $ atelier6.ksh liste_fichiers

Atelier 7 Habillage de la commande find et utilisation de fonctions
Le script atelier7.ksh propose par menu d'utiliser la commande find.
Les critères suivants sont proposés:
  • nom Le script appelle l'option -name de find.
  • proprietaire Le script appelle l'option -user de find. Le script vérifie qu'on donne un "login" existant
  • dates Le script propose dans un sous-menu l'une des options de find suivantes: -mtime, -atime ou -newer

Pour chaque critère, le script fait la saisie au clavier de l'argument correspondant à l'option choisie.
Le script affiche la commande correspondant aux choix de l'utilisateur.
Celle-ci est lancée après confirmation de l'utilisateur.
Le script permet d'interrompre l'exécution de la commande find sans quitter le programme complet.

Appel: $ atelier7.ksh

Atelier 8 Traitement de la ligne de commande
Ecrire un script atelierS. ksh qui traite la ligne de commande de la façon suivante:
Si on a saisi "-u user" Le script affiche le nom des groupes de "user"
après vérification qu'il s'agit d'un "user" existant.
Sans l'option, il affiche ses propres groupes.
  • "- t" Le script affiche le type de terminal de connexion.
•
S'il y a des arguments, le script les affiche tels quels.

Note: Il est possible d'utiliser getopts
Appel: $ atelier8.ksh [ -u user] [ -t ]



Annexe B: Corrections des exercices


B.1 CORRIGES DE TP PROGRAMMATION SHELL

TP1 Traitement de la ligne de commandes et utilisation de la commande test sur les fichiers
  • Ecrire un script tp1.ksh qui reçoit un fichier en argument
  • Le script vérifie qu'un argument est passé sur la ligne de commandes
  • Si c'est un répertoire, le script liste son contenu avec ls
  • S'il s'agit d'un fichier ordinaire "texte", le script l'affiche en mode paginé avec more
•Appel: $ ./tp1.ksh fichier

#!/bin/ksh 
# 
# tp1. ksh 
# 
# Appel: ./tp1.ksh fichier 
# 
# Auteur : JM Lacoste 
# 
# 
################################################################################

### Verifier qu'un seul argument est passe et le placer dans la variable FICHIER 
if [ $# != 1 ]
then 
    echo "Usage : $0 fichier" 
    echo "Au revoir" 
    exit 1 
else 
    FICHIER=$1
fi

### Tester si c'est un repertoire alors 1s 
if [ -d $FICHIER ] 
then
    echo "$FICHIER est un repertoire"
    echo "Liste du contenu de $FICHIER" 
    echo "****************************************************" 
    1s $FICHIER 
fi

### Tester si c'est un fichier simple alors more
if [ -f $FICHIER ]
then
    more $FICHIER
fi

exit 0


TP1-bis Traitement de la ligne de commandes et utilisation de la commande test sur les fichiers
  • Idem TP1, avec le test en syntaxe Korn Shell
  • Le nom du script est tp1bis.ksh
Appel: $ . /tp1bis.ksh fichier

#!/bin/ksh 
# 
# tplbis.ksh 
# 
# Appel: ./tplbis.ksh fichier 
# 
# 
# 
# 
################################################################################ 
### Verifier qu'un seul argument est passe et le placer dans la variable FICHIER 
if [[ $# == 1 ]]
then 
    FICHIER=$1
else
    echo "Usage : $0 fichier" 
    echo "Au revoir" 
    exit 1 
fi

### Tester si c'est un repertoire alors 1s 
if [[ -d $FICHIER ]]
then
    echo "$FICHIER est un repertoire"
    echo "Liste du contenu de $FICHIER"
    echo "********************************************************"
    ls $FICHIER
fi

### Tester si c'est un fichier simple alors more
if [[ -f $FICHIER ]]
then
    more $FICHIER 
fi

exit 0


TP2 Exemple de boucle for
Ecrire un script tp2.ksh qui liste dans une boucle for les commandes d'un répertoire donné en argument.
S'il n'y a aucun argument, le scripte traite le répertoire courant.
Note: Une commande est un fichier ordinaire et exécutable
Appel: $ . / tp2.ksh [ fichier ]

#!/bin/ksh 
# 
# tp2.ksh 
# 
# Appel: ./tp2.ksh [ repertoire ]
# 
# 
# 
# 
################################################################################ 
### Verifier le nombre d'arguments 
case $# in
	0) 
    	REP=$PWD 
	1) 
    	if [ -d $1 ]
    	then 
        	REP=$1 
    	else
        	echo "L'argument doit eCre un repertoire ... "
        	echo " et $1 n'est pas un repertoire ... Au revoir ..."
        	exit 2
    	fi

	;;
	*)
	    echo "Usage : $0 [ repertoire ]"
		echo "Au revoir" 
		exit 1
	;;
esac

### Boucler sur les elements contenus dans le repertoire 
### En verifiant que ce sont des commandes executables (bit x). 
for i in `ls $REP`
do
    if [ -x ${REP}/$i -a -f ${REP}/$i ]
    then 
        printf "%-15s est une commande executable.\n" "${REP}/$i" 
    fi
done 

exit 0


TP2-bis Exemple de boucle for et d'utilisation des expressions arithmétiques
Idem TP2, avec le comptage du nombre de commandes situées dans le répertoire. Le nom du script est tp2bis.ksh.
Appel: $ . / tp2bis. ksh [ fichier ]

#!/bin/ksh 
# 
# tp2bis.ksh 
# 
# Appel: ./tp2bis.ksh [ repertoire ]
# 
# 
# 
# 
############################# 
### Initialisation des variables
NBEXEC=O ### Compteur d'executables

### Verifier le nombre d'arguments
case $# in
        0 ) 
			REP=$PWD
		;;
		1 )
			if [ -d $1 ]
			then
					REP=$1
			else
					echo "L'argument doit etre un repertoire..."
					echo " et$1 n'est pas un repertoire... Au revoir..."
					exit 2
			fi 
		;;
		* ) 
			echo "Usage : $0 [ repertoire ]"
			echo "Au revoir" 
			exit 1
		;;	
esac

### Boucler sur les elements contenus dans le repertoire
### En verifiant que ce sont des commandes executables (bit x).
for i in `ls $REP` 
do
	if [ -x ${REP}/$i -a -f ${REP}/$i ]
	then 
		printf "%-15s est une commande executable.\n" "${REP}/$i" 
		NBEXEC=`expr $NBEXEC + 1` 
	fi
done

echo "================="
echo " Il y a $NBEXEC executables dans le repertoire $REP"

exit 0


TP3 Exemple de boucle while et de lecture clavier
Ecrire un script tp3.ksh qui affiche un message au terminal à une heure donnée. Il récupère l'heure du système sous la forme hh :mm.
Il réalise la lecture au clavier d'une heure au même format hh :mm.
Il vérifie dans le cas d'une saisie non vide que l'heure est postérieure sinon il quitte le programme.
Dans une boucle while, le script attend cette heure en recalculant l'heure système toutes les 10 secondes pour afficher un message au terminal de l'utilisateur.
Note : Penser à utiliser la commande date avec le format suivant date +%H :%M
Appel: $ ./tp3.ksh
#!/bin/ksh 
# 
# tp3.ksh 
# 
# Appel ./tp3.ksh 
# 
# 
# 
# 
############################# 
HEURE='date +%H:%M'
while true
do
	echo "Il est 'date +%H:%M'" 
	read clavier

	echo "clavier : $clavier"

	### Comparer la reponse a l'heure systeme
	### Si HeureSaisie <= HeureSys ok, sinon sortie
	if [ -z $clavier ]
	then
		echo "Au revoir."
		exit 0
	else
		while [ "$HEURE" != "$clavier" ]
		do
			HEURE='date +%H:%M' 
			echo $HEURE 
			sleep 10
		done
	fi 

banner "Et voila." 

done

exit 0


TP4 Exemple d'aiguillage case
Ecrire un script tp4.ksh qui reçoit deux noms de fichiers fic1 et fic2 en arguments.
Le traitement est une boucle sur la lecture des informations au clavier.
La fin fin de la boucle a lieu sur saisie vide.
A l'aide de l'aiguillage case, les lignes ne comportant que des lettres sont ajoutées dans le fichier fiel, les lignes ne comportant que des chiffres sont ajoutées dans le fichier fic2. Les autres lignes sont rejetées Le script affichera le nombre de lignes pour les trois cas en fin de traitement. Appel: $ . / tp4 . ksh fiel fie2 Echo "Le fichier/rep $fic existe deja ... Au revoir .. exit 1 #!/bin/ksh # # tp4.ksh # # Appel: ./tp4.ksh fic1 fic2 # # # # ############################# ### Initialisation des variables ### Fonctions du programme function usage { Echo echo "Usage : $0 fic1 fic2" echo ### Tester qu'on a bien 2 arguments et que ce sont des fichiers inexistants, ### sinon sortir. if [ $# ! = 2 J then usage exit 1 fi for fic in $1 $2 do if [ -e /tmp/$fic then fi done FICA=/tmp/$l FICD=/tmp/$2 ### while true do read clavier case $clavier in + ( [a-zA-ZJ [a-zA-ZJ ) Echo "Un alpharr echo $clavier $FICA + ( [0-9J (O-9J) ) Echo I1Un digitll echo $clavier » $FICD

### Nettoyage rm $FICA $FICB echo "Au revoir ... " exit 0 ### Affichage des duex fichiers echo IIFichier des alphas" eche ,,===================11 cat $FICA echo "Fichier des digits" echo ,,========::::=========11 cat $FICD * ) esac done ### Pour une fois, cette clause ne peut pas etre atteinte. exit 0

TP 5 Instruction select , Expressions arithmétiques et tableaux
Ecrire un script tpS. ksh qui réalise une opération sur 2 entiers Les opérations suivantes sont disponibles : Addition, Soustraction, Division, Multiplication La structure select du Korn Shell est utilisée pour valider le type dopération souhaitée, afficher la liste des toutes ces opérations et sortir du script. Après saisie des 2 entiers, le script vérifie que les nombres sont des entiers et réalise l'opération demandée par l'utilisateur Appel: $ . /tp5. ksh 'expr $1 \. $2'" #!/bin/ksh # # tpS.ksh # # Appel: ./tpS.ksh # # # # ############################# ### Initialisation des variables typeset -i un typeset -i deux ### Fonctions du programme function add { echo "$1 + $2 ~ 'expr $1 + $2'" } function sub { echo "$1 - $2 } function mul { echo 11$1 . $2 } function div { echo "$1 / $2 'expr $1 - $2\11 'expr $1 / $2' (division entiere)" } function catcherr ( echo "On avait dit deux entiers ... :_) ,II echo "Au revoir." exit 1 trap catcherr ERR ### Saisir 2 valeurs ###clear echo IIBonjour," print "Veuillez saisir 2 valeur entieres (par ex. 3 5) \c" read un deux ### Verifier que ce sont deux entiers ### Proposer une operation PS3="Que voulez vous faire avec Sun et $deux (1-4, 5-quitter, ret-menu) ? Il select op in addition soustraction multiplication division quitter do case $REPLY in 1 ) add Sun $deux ;; 2 ) sub Sun $deux

echo "Impossible, merci de donner une valeur entre 1 et exit 1 3 ) mul Sun $deux 4 ) div Sun $deux 5 ) echo "Au revoir ... 11 exit 0 * ) esac dane ### exit 0

Et avec la fonction modulo ... } function sub { echo "$1 - $2 'expr $1 - $2\11 #! jbinjksh # # tpSbis.ksh # # Appel: .jtpSbis.ksh # # # # ############################# ### Initialisation des variables typeset -i un types et -i deux ### Fonctions du programme function add { echo "$1 + $2 ~ 'expr $1 + $2'" function rouI { echo "$1 * $2 } function div { Echo "$1 / $2 } function rnod { Echo n$1 % $2 Echo "$1 $2 'expr $1 \* $2 '" 'expr $1 / $2' (division entiere)" 'expr $1 % $2\11 'expr $1 / $2', reste 'expr $1 % $2 '" } function catcherr { Echo "On avait dit deux entiers ... :_) ,II Echo "Au revoir. 11 exit 1 trap catcherr ERR ### Saisir 2 valeurs ###clear Echo IIBonjour, Il print "Veuillez saisir 2 valeur entieres (par ex. 3 5) \cn read un deux ### Verifier que ce sont deux entiers ### Proposer une operation PS3="Que voulez vous faire avec Sun et $deux (1-5, 6-quitter, ret-menu) ? select op in addition soustraction multiplication division modula quitter do case $REPLY in 1 ) add Sun $deux , , 2 ) sub Sun $deux , , 3 ) mul Sun $deux ii 4 ) div Sun $deux , , 5 ) mod Sun $deux , , 6 ) Echo IIAu revoir ... 11 exit 0

echo IIImpossible, merci de donner une valeur entre 1 et exit 1 . ) esac done ### exit 0

TP6 Exemple de traitement des interruptions, utilisation des fonctions et de la boucle while Ecrire un script tp6. ksh qui réalise dans une boucle infinie while la création puis le grossissement d'un fichier par la redirection d'un message dans le fichier. Le script intercepte les signaux INT, QUIT et TERM comme suit • Ignore le signal QUIT ( 3 ) • Sur réception du signal INT ( 2 ) ou TERM ( 15), appelle une fonction de déroutement qui supprime le fichier Appel: $ ./tp6.ksh touch $FICHIER #!/bin/ksh # # tp6.ksh # # Appel: ./tp6.ksh # # # # ############################# ### Initialisation des variables FICHIER=/tmp/fic$$ if [ -e $FICHIER 1 then else echo "Le fichier $FICHIER existe deja ... Je sors." exit 1 fi ### Fonctions du programme function catchINT { echo "Vous avez tape un kill -2 (INT) programme 11 } function catchQUIT echo "Vous avez tape un kill -3 (QUIT) programme" } function catchTERM echo "Vous avez tape un kill -15 (TERM) programme" ls -al $FICHIER cat $FICHIER echo "Suppression du fichier $FICHIER dans 5 sec. Il sleep 5 rm $FICHIER echo "Au revoir. Il exit 0 echo go ### Interceptions trap catchINT INT trap catchQUIT QUIT trap catchTERM TERM ### Tester l'existence du fichier de depart et le creer si necessaire ### Fonctions du programme while true

date » $FICHIER sleep 5 do done exit 0

B.2 CORRIGES D'EXERCICES SUR LES FILTRES Dans la suite la référence au fichier" exemple" est faite à partir du contenu vu ci-dessous rager rene marie Marcel paul rager Rene marie marie Sophie Sylvie Paul michel Mireille Paul Rene Paul Andre martin 12000 cd1 duval 500 cd1 pervenche 12010 cd3 dupond 600 cd2 martin 10000 cd4 martin 12500 cd1 DUVAL 510 cd1 pervenche 13000 cd3 martin 13000 cd3 Martinez 6512 cd2 Martinelli 45678 cd2 Legrand 4560 cd5 DUVAL 54500 cd1 Duvalier 12345 cd2 LEGRAND 14560 cd5 Pervenche 5400 cd3 martinez 5600 cd2 dupond 650 cd5 Exercice 1 Utilitaire de tri sort sur le fichier exemple 1) Trier sur le troisième champ en ordre décroissant Marcel Rene rene $ dupond DUVAL duval 600 cd2 510 cd1 500 cdl $ sort -k3nr exemple michel DUVAL 54500 cd1 Sylvie Martinelli 45678 cd2 Paul LEGRAND 14560 cd5 marie rnartin 13000 cd3 2) Trier sur le deuxième champ ( minuscules et majuscules confondues) $ sort -bf -k2 exemple Marcel dupond 600 cd2 Andre dupond 650 cd5 rene duval 500 cd1 Rene DUVAL 510 cd1 marie pervenche 12010 cd3 marie pervenche 13000 cd3 $ 3) Trier sur le deuxième champ ( minuscules et majuscules confondues ), puis deuxième passage sur le premier champ ( même critère), puis troisième passage sur le troisième champ marie Rene $ pervenche Pervenche 13000 cd3 5400 cd3 $ sort -bf -k2,2 -k1,1 -k3n,3n exemple Andre dupond 650 cd5

4) Trier sur les trois premiers caractères du deuxième champ ( critère code ascii ) $ sort Rene michel Mireille Paul -k2b,2.3b exemple DUVAL 510 DUVAL 54500 Duvalier 12345 LEGRAND 14560 cd1 cd1 cd2 cd5 rager marie marie $ martin pervenche pervenche 12500 cd1 12010 cd3 13000 cd3

Exercice 2 Utilitaire de tri sort sur des commandes ou fichiers du système 1) Trier le résultat de "ls -al" d'après la taille des fichiers $ ls -al 1 sort -n -k5 total 49 -rw-r--r-- 1 stage13 stage 25 Feb 8 17:25 .exrc -rw-r--r-- 1 stage13 stage 264 Feb 8 17:25 .kshrc -rwxr--r-- 1 stage13 stage 350 Feb 8 17:25 .xsession -rwxr----- 1 stage13 stage 367 Feb 8 17:25 .profile drwxr-xr-x 2 stage13 stage 512 Feb 25 12:28 -rwxr- -r-- 1 stage13 stage 943 Feb 20 15:56 deuxierne drwxr-xr-x 33 raot system 1024 Feb 24 23:20 -rw-r----- 1 stage13 stage 1206 Feb 25 13: 59 exemple $ 2) Trier le fichier letc/passwd d'après le numéro de login ( UID ) en ordre décroissant $ sort -t: -nr k3 /etc/passwd stage2:! :1002:1000:Compte_Formation:/home/stage2:/usr/bin/ksh stage1:! :1001:1000:Compte_Formation:/home/stagel:/usr/bin/ksh guest:! :100:100: :/home/guest: lpd:! :9:4294967294: :/: uucp:! :5:5: :/usr/lib/uucp: adm:! :4:4: :/var/adm: sys:! :3:3: :/usr/sys: $

2) Remplacer, dans le résultat de "Is -al", tout caractère n'étant ni un chiffre, ni un espace, ni un saut de ligne par la lettre X $ ls -al 1 tr -c "[0-9] \012" " [X.] " XXXXX 14 XXXXXXXXXX 2 XXXXX13 XXXXX 512 XXX 25 12X28 X XXXXXXXXXX 33 XXXX XXXXXX 1024 XXX 24 23X20 XX XXXXXXXXXX 1 XXXXX13 XXXXX 0 XXX 9 08X38 XXXXXXXXXXX XXXXXXXXXX 1 XXXXX13 XXXXX 196 XXX 8 17X25 XXXXXX XXXXXXXXXX 1 XXXXX13 XXXXX 25 XXX 8 17X25 XXXXX XXXXXXXXXX 1 XXXXX13 XXXXX 264 XXX 8 17X25 XXXXXX XXXXXXXXXX 1 XXXXX13 XXXXX 241 XXX 8 17X25 XXXXXX

Exercice 4 Recherche d'expressions avec grep sur le fichier exemple 1) Rechercher les lignes du fichier" exemple" qui commencent par m ou M. $ grep " [mM] , exemple marie pervenche 12010 cd3 Marcel dupond 600 cd2 marie pervenche 13000 cd3 marie martin 13000 cd3 michel DUVAL 54500 cd1 Mireille Duvalier 12345 cd2 $ 2) Rechercher les lignes du fichier" exemple" qui comportent la lettre a en deuxième position. $ grep , ' .a' exemple marie pervenche 12010 cd3 Marcel dupond 600 cd2 paul martin 10000 cd4 marie pervenche 13000 cd3 marie martin 13000 cd3 Paul Legrand 4560 cd5 Paul LEGRAND 14560 cd5 Paul martinez 5600 cd2 $ 3) Rechercher les lignes du fichier" exemple" qui se terminent par l ou 2. $ grep , [12] $' exemple rager martin 12000 cd1 rene duval 500 cd1 Marcel dupond 600 cd2 rager martin 12500 cd1 Rene DUVAL 510 cd1 Sophie f\'lartinez 6512 cd2 Sylvie Martinelli 45678 cd2 michel DUVAL 54500 cdl Mireille Duvalier 12345 cd2 Paul martinez 5600 cd2 $ 4) Rechercher les lignes du fichier" exemple" qui commencent par une majuscule OU qui se terminent par la chaîne" cdl" . DUVAL Martinez Martinelli Legrand DUVAL Duvalier LEGRAND Pervenche rnartinez dupond 12000 500 600 12500 510 6512 45678 4560 54500 12345 14560 5400 5600 650 cd1 cd1 cd2 cd1 cd1 cd2 cd2 cd5 cd1 cd2 cd5 cd3 cd2 cd5 $ egrep rager rene Marcel rager Rene Sophie Sylvie Paul michel Mireille Paul Rene Paul Andre $ " [A-Z] 1 cd1$' exemple martin duval dupond martin

5) Rechercher les lignes du fichier" exemple" qui commencent par une majuscule ET qui se terminent par la chaîne" cd2" ( avec le résultat trié sur le troisième champ en ordre décroissant ). $ grep "[A-Z] .• cd2$' exemple Sylvie Martinelli Mireille Duvalier Sophie Martinez Paul martinez Marcel dupond $ 1 sort -nr -k3,3 45678 12345 6512 5600 600 cd2 cd2 cd2 cd2 cd2

Exercice 5 Recherche d'expressions avec grep sur le fichier / etc/passwd 1) Dans le fichier /etc/passwd, rechercher les lignes correspondant aux utilisateurs du Korn-shell. $ $ grep 'bin/ksh *$' /etc/passwd root:! :0:0: :/:/bin/ksh netinst:*:200:1: :/home/netinst:/usr/binlksh stagel:! :lOOl:lOOO:Compte Formation:/home/stagel:!usr!bin/ksh stage2:! :1002:1000:compte=Formation:/home/stage2:!usr!bin!ksh stage3:! :1003:1000:Compte_Formation:!home!stage3:!usr/bin/ksh 2) Même question pour les utilisateurs potentiels du Bourne-shell. $ grep -e 'bin/sh' *$ -e ': *$' /etc/passwd ou encore $ egrep 'bin/sh *$ 1: *$' /etc/passwd ( quand le dernier champ est vide, le shell par défaut est le "Bourne"

sed sur Exercice 6 Edition non interactive de fichiers le fichier exemple 1) Dans les lignes du fichier" exemple" qui ne contiennent pas la chaîne » cdl" , remplacer la chaîne" cd" par la chaîne" code" . '/cd1/1s/cd/code/' exemple martin duval pervenche dupond rnartin martin DUVAL pervenche martin Martinez Martinelli Legrand $ sed rager rene marie Marcel paul roger Rene marie marie Sophie Sylvie Paul 12000 500 12010 600 10000 12500 510 13000 13000 6512 45678 4560 $ cdl cdl code3 code2 code4 cdl cd1 code3 code3 code2 code2 code5 2) Afficher le fichier" exemple" jusqu'à trouver la chaîne" cdS" ( ligne non comprise) . $ sed '/cd5/q' exemple 1 sed '$d' roger rnartin 12000 cd1 rene duval 500 cdl marie pervenche 12010 cd3 Marcel dupond 600 cd2 paul martin 10000 cd4 rager martin 12500 cdl Rene DUVAL 510 cd1 marie pervenche 13000 cd3 marie martin 13000 cd3 Sophie Martinez 6512 cd2 Sylvie Martinelli 45678 cd2 $ 3) Décaler, de quelques espaces, le début des lignes du fichier" exemple" commençant par une majuscule $ sed '/-[A-Zj/s/-/ /' exemple rager martin rene duval marie pervenche Marcel dupond paul martin rager martin Rene DUVAL marie pervenche marie martin Sophie Martinez Sylvie Martinelli Paul Legrand michel DUVAL Mireille Duvalier 12000 500 12010 600 10000 12500 510 13000 13000 6512 45678 4560 54500 12345 $ cd1 cdl cd3 cd2 cd4 cdl cd1 cd3 cd3 cd2 cd2 cd5 cd1 cd2 4) Mettre des parenthèses autour des lignes du fichier" exemple" qui se terminent par" cdl"

$ sed '/cd1$/s/ .• /(&)/' exemple (roger martin 12000 cdl) (rene duval 500 cd L) marie pervenche 12010 cd3 Marcel dupond 600 cd2 paul martin 10000 cd4 (roger martin 12500 cd l ) (Rene DUVAL 510 cd l ) marie pervenche 13000 cd3 marie martin 13000 cd3 Sophie Martinez 6512 cd2 Sylvie Martinelli 45678 cd2 Paul Legrand 4560 cd5 (michel DUVAL 54500 cdl) $ 5) Idem" question 4" mais en n'affichant que les lignes modifiées, triées sur le deuxième champ ( minuscules et majuscules confondues) avec une deuxième passe sur le troisième champ en ordre décroissant $ sed '/cdl$/s/ .• /(&)/' exemple (michel DUVAL (Rene DUVAL (rene duval (rager martin (rager martin $ 1 grep "(' 1 sort k2bf,2 54500 510 500 12500 12000 k3nr,3 cdl) cd l ) cd l.) cdl) cdl) 6) Remplacer tous les" 0" du fichier exemple par des" x" et tous les" 1" par des "y" $ cat commande s/o/x/g s/I/Y/g $ $ sed -f commande exemple rager martin Y2XXX cdY rene duval 5XX cdY marie pervenche Y2XYX cd3 Marcel dupond 6XX cd2 paul martin YXXXX cd4 rager martin Y25XX cdY Rene DUVAL 5YX cdY marie pervenche Y3XXX cd3 marie martin Y3XXX cd3 Sophie Martinez 65Y2 cd2 Sylvie Martinelli 45678 cd2 Paul Legrand 456X cdS michel DUVAL 545XX cdY Mireille Duvalier Y2345 cd2 Paul LEGRAND Y456X cdS Rene Pervenche 54XX cd3 Paul martinez 56XX cd2 Andre dupond 65X cdS $

Exercice 7 Traîternent sur le fichier exemple avec l'outil awk 1) Afficher le fichier en numérotant les lignes et en permutant les deux premières colonnes. $ awk '{ print NR , $2 , $1 , $3 ,$4 }' exemple $ awk '{print NR, $2, $1, $3, $4}' exemple 1 martin roger 12000 cd1 2 duval rene 500 cd1 3 pervenche marie 12010 cd3 4 dupond Marcel 600 cd2 5 martin paul 10000 cd4 6 martin roger 12500 cdl 7 DUVAL Rene 510 cdl 8 pervenche marie 13000 cd3 9 martin marie 13000 cd3 10 Martinez Sophie 6512 cd2 Il Martinelli Sylvie 45678 cd2 12 Legrand Paul 4560 cd5 13 DUVAL michel 54500 cd1 14 Duvalier Mireille 12345 cd2 15 LEGRAND Paul 14560 cd5 16 Pervenche Rene 5400 cd3 17 martinez Paul 5600 cd2 18 dupond Andre 650 cd5 $ 2) Afficher noms et prénoms des personnes correspondant aux codes "cd1" ou "cd2". $ awk $4 "cdl" Il $4 "cd2" END { printf "Total ~ %d\n" r n exemple martin roger cdl duval rene cdl dupond Marcel cd2 martin roger cd1 DUVAL Rene cd1 Martinez Sophie cd2 Martinelli Sylvie cd2 DUVAL michel cd1 Duvalier Mireille cd2 martinez Paul cd2 Total ~ 10 $ $2 , $1 , $4 n++ } { print } 3) Afficher la ligne pour laquelle le nombre ( 3ème colonne) est le plus grand. $ awk $3 > max END exemple michel $ max ~ $3 print ligne ligne } $0 DUVAL 54500 cd1 4) Pour chaque code, afficher le total des nombres ( 3ème colonne ). Afficher en final la moyenne des nombres.

} exemple cd1 80010 cd2 70735 cd3 43410 cd4 10000 cdS 19770 Moyenne des nombres $ 12440,277778 $ awk ' { END ( tab[$41 +~ $3 total +~ $3 for ( code in tab) print code, tab[codeJ printf "Moyenne des nombres ~ %f\n" , total / NR

B.3 CORRIGES D'EXERCICES DE L'ATELIER DE PROGRAMMATION SHELL Atelier 1 Modification de nom de fichiers avec confirmation éventuelle et gestion de la ligne de commandes Ecrire un script atelierl.kshqui recoit deux arguments .extl et .ext2. Le but du script est de renommer tous les fichiers d'extension. extl du répertoire courant en *. ext2. Le script vérifiera que les arguments sont des" extensions:" "suivi de l'extension en minuscules. Si on donne l'option" - i " , le script propose la confirmation pour chaque fichier. Note: Penser à utiliser la commande basename sur les noms de fichiers à traiter Syntaxe: $ basename string [suffix] Appel: $ atelierl. ksh [ -i .extl .ext2 mauvais_appel #!/bin/ksh # atelier1 function mauvais_appel echo "Usage: $0 [-il .ext1 .ext2\n" exit 1 function mauvais arg { - if [[ $1 != @(.+([a-z]» Il $2 != @(.+([a-z])]] then return 0 else return 1 fi conf=O if test $# -gt 3 -0 $# -lt 2 then mauvais_appel fi if test $# -eq 3 ; then if test $1 = -i then conf=1 shift el se fi fi if mauvais_arg $1 $2 then

integer nombre=O for f in *$1 do # si aucun fichier d'extension $1 n'existe, on sort if test $f "*$11'; then Echo uII n'y a pas de fichiers d'extension $111 exit 2 mauvais_appel fi fi if test $eonf = 1 ; then read rep? Il Renommer $f (a/n) . 11 if test -il II$rep'l ; then if test $rep = 0 ; then newname=$(basename $f $1)$2 rnv $f $newname nombre::::nombre+l fi fi else newname=$(basename $f $1)$2 rnv $f $newname nombre=nombre+l fi done Echo IINombre de fichiers renommes $nombre"

Atelier 2 Autre script de modification de nom de fichiers Ecrire un script atelier2 .ksh qui recoit des noms de fichiers en arguments. Pour chaque argument, s'il s'agit d'un fichier ordinaire dont le nom ne contient que des MAJUSCULES, on le renomme en minuscules. Appcl: $ atelier2.ksh liste_fichiers #l/usr/bin/ksh # atelier2 typeset -i nombre=O for f in $* do if [[ $f = + ([A-Z]) ]] then if test -f $f then newname=$(echo $f 1 tr 00 [A-Z] 00 00 [a-z] 00) echo "On renomme $f en $newnarne" mv $f $newname nombre=nombre+l fi fi done echo "Nombre de fichiers renommes $nombre"

Atelier 3 Traitements sur les fichiers : test Ecrire un script atelier3 . ksh qui recoit des noms de fichiers en arguments. Si le fichier existe et est un fichier ordinaire, on affiche sa taille. Si le fichier n'existe pas, on le créée de taille O. Si l'option" -c" est utilisée, le script ne créée pas le fichier s'il n'existe pas. Appel: $ atelier3.ksh [ -c ] liste_fichiers fi #! /usr/bin/ksh # atelier3 if test $# -ne 0 then if test $1 -c then option=o shift if test $# -eq 0 ; then Echo 11Usage : $0 [-el liste de fichiers Il exit 1 fi else option=n fi for f in $* do if test -e $f then if test -f $f ; then t.ad LLe » 'wc -c $f 1 awk "{p r Lnt. s i }: , Echo l'Taille de Sf = $taille octet(s) Il fi el se if test $option = 0 then Echo IIOption -c demandee je ne cree pas $fll else > $f Echo rrCreation de $f ( taille 0 ) Il fi done fi

Atelier4 Menu simple avec case et appel de commandes UNIX Ecrire un script atelier4. ksh sous la forme d'un menu dans une boucle until. Le script prévoit avec la structure case : 1. L'affichage de l'heure 2. Le changement de répertoire courant 3. La sauvegarde au format tar compressé des fichiers ordinaires du répertoire courant après avoir vérifié qu'il y en a Après saisie du nom de l'archive souhaité, la création de celle-ci se fait sous jtmp 4. La liste du contenu d'une archive dont on saisit le nom 5. La Restauration interactive de fichiers d'une archive 6. a La Sortie Rappel sur la syntaxe de tar : Création d'une archive: tar -cvf fichier_archive lis te_a_sauvegarder Lecture d'une archive: tar -tvf fichier_archive Imore Restauration d'une archive tar -xvf fichier_archive liste_a_restaurer Appel: $ atelier4.ksh #! /bin/ksh # atelier4 fin=O ; clear fictemp=/tmp/liste$$ until test "$rep" = $fin do cat «'FIN MENU' O. SORTIE 1. QUELLE HEURE EST-IL? 2. CHANGEMENT DE REPERTOIRE COURANT 3. SAUVEGARDE ( ARCHIVE TAR COMPRESSEE 4. LISTE D'UNE ARCHIVE 5. RESTAURATION INTERACTIVE FIN MENU read rep?"Votre choix case "$rep" in $fin) echo "Au revoir et Mercin exit 0 1) echo "\nll est 'date '+%H h %M' '\nl! 2) echo "Nouveau repertoire ( ou Return ou home) \clI read fie if [ -n l1$ficlI ] then

if [$fic home 1 then cd elif [ -d $fic -a -x $fic J then cd $fic el se Echo n\n?? Changement de repertoire impossible. Il fi fi Echo lI\nRepertoire courant $PWD\n" 3) > $fictemp n=O for i in .7?* * do if test -f $i ; then Echo $i » $fictemp let TI=n+1 fi done if test $n -gt 0 then echo "Il y a $n fichiers dans $PWD" read archive?"Norn de l'archive ( Return pour abandonner) . 11 if test -il l'$archive'' then tar cvf - 'cat $fictemp' 1 compress > /tmp/${archive}.tar.Z Echo IISauvegarde $archive effectueell fi rm -f $fictemp else Echo 1'11 n'y a pas de fichiers ordinaires dans $PWD'1 fi ii 4) read archive? Il Nom de l'archive ( Return pour abandonner) if test -n l'$archive'l then fic=/tmp/${archive}.tar.Z if test -f $fic ; then uncompress < $fic 1 tar tvf - el se Echo ,'?? L'archive SEie n'existe pas" fi fi i : 5) read archive?IINom de l'archive ( Return pour abandonner) if test -il Il $archive Il then fic=/tmp/${archive}.tar.Z if test -f $fic ; then Echo "Fichier a restaurer \clI read nom if test -TI lI$nom" i then uncompress < $fic 1 tar xvf - $nom fi else Echo "?? L'archive $fic n'existe pas" fi fi ii *) echo 1177 Choix irnpossible\nl1 ii esac if test l'$rep'l != $fin then

echo "TAPEZ RETURN POUR CONTINUER \c" ; read bidon clear fi done

Atelier 5 Gestion de la ligne de commande et traitement sur les fichiers Ecrire un script atelierS. ksh qui reçoit en premier argument un entier puis une liste de fichiers. Le script vérifie que le premier argument est un entier. Il affiche pour chaque fichier les lignes plus longues que cette valeur et le nombre de lignes. App~: $ atelierS.ksh valeur liste_fichiers #! /bin/ksh # atelierS if test $# -lt 2 then Echo "Usage $0 longueur liste de fichiersll exit l fi if [[ $1 +([0-9])]] then longueur~$l else Echo 11Usage $0 longueur liste de fichiers" exit 1 fi selection=111ength > $ln shift for f in $_ do Echo f!Fichier $f : Lignes plus longues que $longueur caracteres" awk Il $selection {print; n++ } END { if ( n > 0 ) printf \"Nombre de lignes $f %s\n\" , n } done

Atelier 6 Traitements sur les fichiers et Expressions arithmétiques Ecrire un script atelier6 .ksh qui reçoit une liste de noms de fichiers en arguments. Le script ne conserve de la liste d'arguments que les fichiers ordinaires et affiche la taille en octets de chacun, la taille totale ainsi que le nom du plus gros fichier. Appel: $ atelier6.ksh liste_fichiers taille += $5 if ( $5 > max ) { fic=$9 ; tfic=$5 max=$5} n++ printf "%16d\t%s\n", $5, $9 #! /hin/ksh # atelier6 integer i=O for arg in $_ do if test -f $arg ; then liste [il =$arg i~i+l fi done if (( i = = 0 » ; then echo IILa liste d'arguments ne contient pas de fichiers ordinaires!!U exit 1 fi ls -1 ${liste [-l} awk ' BEGIN NF > 2 printf "%s\t%s\n","TAILLE EN OCTETS","FICHIERS" 1 max=O } END printf "TAILLE TOTALE : %d ( %d fichiers) \n", taille, n printf "LE PLUS GROS: %s ( %d octets )\n",fic,tfic

Atelier 7 Habillage de la commande find et utilisation de fonctions Le script atelier7 . ksh propose par menu d'utiliser la commande find. Les critères suivants sont proposés : • nom Le script appelle l'option -name de find. • proprietaire Le script appelle l'option -user de find. Le script vérifie qu'on donne un "login" existant • dates Le script propose dans un sous-menu l'une des options de find suivantes: -mtime , -atime ou -newer Pour chaque critère, le script fait la saisie au clavier de l'argument correspondant à l'option choisie. Le script affiche la commande correspondant aux choix de l'utilisateur. Celle-ci est lancée après confirmation de l'utilisateur Le script permet d'interrompre l'exécution de la commande find sans quitter le programme complet. Appcl: $ atelier7.ksh function lit_reponse { # Premier argument # Deuxieme argument print 1'\n$1 : \CII read $2 la question la variable receptionnant la reponse Il! /bin/ksh Il atelier7 function ok commande Il Affiche la commande a lancer. # Retourne 0 si ok pour la lancer et 1 sinon print •OK pour: find $1 $2 $3 -print (o/n) \c• typeset -1 reponse read reponse if [ "$reponsett = 0 then return 0 else return 1 fi function veriE login { - # Retourne 0 si l'argument est un login sur le systeme grep •'$1:• /etc/passwd >/dev/null 2>&1 return $? PS3="Votre critere

$ (Liste [2] }) print \\n\\n select j in "Modifies aujourd'huill IIPlus jeune quell liNon accedes depuisll "FinI! do case $REPLY in 1) Annexe B set -A Liste Nom Proprietaire Dates Sortie while test lI$ill (= Sortie do clear select i in ${Liste[*]} do case $i in $(Liste [0] }) critere=-name lit reponse IINom cherchell arg $ (Liste [1] }) critere=-user lit_reponse "Nom du login" arg verif 1091D "$arg" if test $? != 0 then print 1I?? $arg n'est pas un nom de login" print IIReturn pour continuer. \en ; read break fi " critere=-mtime arg=-l break 2) critere=-newer lit reponse "Nom du fichier!! arg break ;; 3) critere=-atime lit_reponse lINombre de jours" arg arg=+"$arg" break 4) break 2 ;; esac done Sortie) print IIAu revoir et merci\n\n" ; break, 1 1111) print "Choix impossible\n\n" i break, f esac lit_reponse "Repertoire" dir if ok_commande lI$dir" n$criteren "$arg" then trap 'break' 2 3 # pouvoir abandonner find par un break clavier find n$dirll n$critere" n$arg" -print 1 more print "Return pour continuer. \c" ; read fi break done trap 2 3 # fin du select # reprise du comportement par defaut done # fin du while

Atelier 8 Traitement de la ligne de commande Ecrire un script atelierS. ksh qui traite La Ligne de commande de La façon suivante: Si on a saisi" -u user" Le script affiche le nom des groupes de "user" après vérification qu'il s'agit d'un "user" existant. Sans l'option, il affiche ses propres groupes . • " - t" Le script affiche le type de terminal de connexion. S'il y a des arguments, le script les affiche tels quels. Note: Il est possible d'utiliser getopts Appel: $ atelier8.ksh [ -u user [ - t ] #! /bin/ksh # atelier8 # exemple de corrig\'e avec utilisation de getopts user~$LOGNAME while getapts ,u,t apt do case Sapt in u) user~$OPTARG # L'argument de -u ne doit pas commencer par un - if [[ $OPTARG 11 then print -u2 "Ue a qe : $0 [ -u user] [ -t ] parametres ... fi exit l fi aptianu~VRAI; ; t) optiont~VRAI;; :) print -u2 11$0 : L'option -$OPTARG requiert un argumentll print -u2 "Usage: $0 [ -u user] [ -t ] parametres exit 1 ;i ?) print -u2 "$0 : -$OPTARG : Option 111ega1ell print -u2 "Usage: $0 [ -u user 1 [ -t 1 parametres exitl;; esac done shift QPTIND-l if [[ "sopt.Lonu'' liVRAI Il ]] then grep 11~$user:l1 /etc/passwd > /dev/null 2>&1 if [[ $? -ne 0 11 then print -u2 lI$user n'est pas un utilisateur de 'uname _n'II else eeho "Les groupes de $userll groups $user fi el se echo liMes groupes: $ (groups) Il fi if [[ Il $optiont Il = liVRAI Il ]] then print IIType du terminal: $TERMII fi if [ $# -ne 0 1 then

1 _ echo "Arguments ~ -------------------------------------------------------------- $*"

Index awk,67,77 tee, 62 test, 25 tr, 66 typeset,46,54 break, 31 case, 35 continue, 31 eut, 62 unset,8 until,30 eval,48 ex, 67 exec,39 export,18 expr,33 whence,48 while,30 Fonctions, 50 getopts,71 Graticiels, 59 grep,67,69 head,61 if, 22 IFS, 42 integer,34 let, 34 nawk,67 printf,47 print,47 read,32 return,53 sed, 67, 74 select, 36 set, 43 shebang,18 shift,42 Signaux, 45 sort, 64 tail,62