$Id: C-csh_n_tcsh.xml,v 1.1.1.1 2006/04/02 16:27:31 Ivan Exp $
Copyright © 2002-2006 Pascal PICARD, Ivan KURZWEG pascal@seth.homeunix.net, ik-r@wanadoo.fr
Permission to use, copy, modify, and distribute this documentation for any purpose with or without fee is here by granted, provided that the above copyright notice and this permission notice appear in all copies.
THE DOCUMENTATION IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS DOCUMENTATION INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS DOCUMENTATION.
Résumé
Le shell est d'abord l'interpréteur de commande d'un système Unix™ mais c'est aussi un quasi langage de programmation interpreté autorisant la récursivité.
Historiquement le premier shell du système Unix™ est le Bourne-Shell (sh). Ce shell n'a cessé d'être amélioré et l'université de Berkeley qui a beaucoup contribué à la branche BSD d'Unix™ a développé le C-Shell (csh), un successeur de sh munit de fonctionnalités étendues par rapport à son ancêtre. Le C-Shell à son tour possède un successeur : TC-Shell (tcsh), ce dernier étend les fonctionnalités de son prédécesseur et apporte davantage de convivialité. Ces caractéristiques en font un équivalent au GNU Bourne-Again-Shell (GNU/bash).
Ces shells syntaxiquement orientés C restent les shells par défaut des flavors BSD et c'est pourquoi nous nous proposons, dans ce support, de les présenter principalement dans un contexte d'interactivité où ils sont plutôt efficaces.
Pour nous joindre : <pascal@seth.homeunix.net> <ik-r@wanadoo.fr>
Le shell est un interpréteur de commande en ligne. Chaque entrée sur un terminal est analysée et décomposée en terme d'instructions à exécuter. Ces instructions peuvent impliquer des commandes internes que le shell connaît et est en mesure d'exécuter directement, ou bien d'autres commandes déclenchant des programmes que le shell va tenter de localiser et de lancer. Le shell dispose d'instructions (structures de contrôle, ...) et de variables qui le rende en partie comparable à un langage de programmation, de sorte que l'on peut écrire des shell scripts, littérallement de petits ou moyens programmes rédigé en shell.
Un interpréteur shell exécutent trois types de commandes :
Les commandes internes [built-in commands], comme par exemple : cd, pwd, umask ... ou bien encore les éléments algorithmiques tels if .. then .. else .. endif, foreach ... ...
Les commandes externes indépendantes du shell et localisées dans les répertoires, comme par exemple : ls (/bin/ls), find (/usr/bin/find) ... Ces commandes nécessitent la création d'un nouveau shell pour leur exécution contrairement à celles relevant de la première catégorie.
Les commandes définies par un alias.
il possède un mécanisme d'historisation et de rappel (et d'éditions des commandes tcsh) ;
il permet le contrôle des processus (suspension), reprise asynchrone (background) ou interactive (foreground)) ;
il permet de traiter les tableaux de caractères ;
il possède des directives de programmation proche du C ;
il possède un mécanisme de completion ;
il permet le calcul arithmétique.
Lors du login, csh exécute les instructions contenues dans le fichier /etc/csh.cshrc puis celles du fichier /etc/csh.login puis celles de ~/.cshrc (tcsh lit le script ~/.tcshrc, s'il existe et sinon ~/.cshrc) et enfin celles de ~/.login. La signification du caractère ~ est donnée en Section 1.5, « Métacaractères et autres caractères spéciaux du shell ». Lors de la fin de session (logout) csh ou tcsh exécutent les commandes des fichiers /etc/csh.logout et ~/.logout, dans cet ordre.
Un sous-shell, ne lit pas les fichiers suffixés en .login à son démarrage ni les fichiers suffixés en .logout à sa terminaison.
De ce qui précède, on déduit que les commandes à exécuter une seule fois pendant une session sont à placer dans les fichiers suffixés en .login (typiquement les variables d'environnement), tandis que les autres sont à placer dans les fichiers suffixés en .cshrc.
Le fichier ~/.cshrc contient typiquement :
la définition des alias ;
la définition des paramètres de fonctionnement ;
l'initialisation des variables.
Exemple 1. fichier ~/.cshrc
# ~/.cshrc
#
# $FreeBSD: src/share/skel/dot.cshrc,v 1.10.2.3 2001/08/01 17:15:46 obrien Exp $#
# .cshrc - csh resource script, read at beginning of execution by each shell
# see also csh(1), environ(7).
#
# Les alias
# -------------------------
alias j jobs -l
alias la /bin/ls -aoBG
alias lf /bin/ls -FABG
alias ll /bin/ls -loABG
alias gv /usr/X11R6/bin/gv -color -safer -quiet \
-media a4 -portrait
alias rm /bin/rm -i
alias wget `which wget` -N -c -S
alias emacs `which emacs` -q
alias gnuplot `which gnuplot` -background ivory
alias xdvi `which xdvi` -fg DarkSlateGray -paper a4
alias xfig `which xfig` -center -centim -pap a4 -po
alias dvips `which dvips` -t a4 -o out.ps
alias h 'history -r \!* | less'
alias psnup `which psnup` -pa4 -2up -m0.5cm
# Paramètres et variables.
# -------------------------
limit coredumpsize 0 # prevent core files from being written to disc
# A righteous umask
umask 077
set prompt='%B%n%b@%m:%c > '
set prompt2='%B%n%b:>> '
set path = (/usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin \
/usr/bin /usr/X11R6/bin $HOME/bin)
set correct = cmd
/usr/X11R6/bin/xrdb -load ~/.Xdefaults >& /dev/null
if ($?prompt) then
# An interactive shell -- set some stuff up
set filec
set history = 2048
set savehist = 2048
set histfile = ~/.history
set mail = (/var/mail/$USER)
set notify
set addsuffix
set autolist
set machbeep = nomatch
set cdpath = ( ~ ~/bin )
set symlinks = ignore
if ( $?tcsh ) then
set echo_style = both
set histdup = all
set savehist = ( 2000 merge )
bindkey "^W" backward-delete-word
bindkey -k up history-search-backward
bindkey -k down history-search-forward
source ~/.tcsh_comp
endif
endif
Le fichier ~/.login contient essentiellement la définition des variables d'environnement.
Exemple 2. fichier ~/.login
# ~/.login setenv LC_CTYPE fr_FR.ISO8859-15 setenv PAGER less setenv MOZILLA_HOME /usr/X11R6/bin/mozilla setenv MACHTYPE i386 setenv EDITOR emacs setenv HOSTTYPE FreeBSD setenv CPUTYPE k7 setenv OSTYPE FreeBSD setenv TEXEDIT emacs setenv VENDOR amd setenv SHLVL 1 setenv LSCOLORS "ExFxbxcxBxdxHBhbafacad" setenv CLICOLOR 1 setenv CLICOLOR_FORCE 1 # COLORTERM to "rxvt" setenv COLORTERM "rxvt" # COLORFGBG to "default" setenv COLORFGBG "default" setenv RSYNC_RSH /usr/bin/ssh setenv CVSROOT /home/cvsroot setenv BLOCKSIZE K setenv TERM xterm-color [ -x /usr/games/fortune ] && /usr/games/fortune freebsd-tips
Le fichier ~/.logout contient essentiellement des commandes de suppression de fichiers inutiles.
Exemple 3. fichier ~/.logout
# ~/.logout
echo -n "clean up before logout ..."
find $HOME \( -type f \
\( -name a.out -o -name "*.bak" -o -name core -o \
-name "#*#" -o -name "#.*#" -o -name "*.o" -o \
-name "*~" -o -name ".*~" \) -exec /bin/rm -f {} \; > /dev/nul
l \)
echo "... done"
echo "last connexion at [`date +%Y-%M-%d` a `date +%H:%I:%S`] pour [`logname`] s
ur [`tty`]" > ~/.deconnex
Il est possible à tout moment et notamment après une modification de réexécuter les fichiers au moyen de la commande source.
$ > source ~/.login $ > source ~/.cshrc
Dans les distributions xBSD on peut voir les deux fichiers suivants : /.login et /.profile (situés à la racine). Ils sont exécutés uniquement dans le mode mono-utilisateur [single-user mode]. Leurs modifications sont à faire avec le plus grand soin.
On parle de variables d'environnement car elles sont « automatiquement » transmises à tous les processus fils du shell, i.e. tous les processus lancés par ce shell.
Les variables qui suivent ont un sens particulier pour le shell (csh et tcsh), elles sont utilisées par certaines commandes du shell ou du système. Parmi elles, argv, cwd, home, path, prompt, shell et status sont toujours définies par le shell. Si l'on exclut les variables cwd et status, leur positionnement intervient seulement à l'initialisation. Ces variables ne sont plus modifiées, sauf éventuellement par l'utilisateur.
Tableau 1. Variables d'environnement
| Variable d'environnement | Sémantique |
|---|---|
argv | Arguments du shell, résultant de la substitution des paramètres positionnels. $argv[1] correspond à $1, $argv[2] à $2 ... |
autologout | [tcsh] Positionné à un certain nombre de minutes, permet de déconnecter automatiquement l'utilisateur au bout de cette période d'inactivité. |
cdpath | Liste de répertoires alternatifs dans lesquels sera effectuée la recherche des sous-répertoires lors de l'utilisation de la commande cd avec un argument de type nom relatif. |
correct | [tcsh] Positionnable à all ou cmd. Dans le deuxième cas, permet la correction des erreurs de typos sur les noms de commandes. |
cwd | Chemin absolu du répertoire courant. |
echo | |
filec | Permet la completion des noms de fichiers. |
histchars | Chaîne de caractères à utiliser dans les substitutions de l'historique. Les éléments de cette chaîne remplacent les caractères standards, ainsi le premier caractère de cette chaîne remplace le '!', le second remplace le '^' ... |
histfile | Chemin d'accès au fichier d'historique. |
history | Permet de contrôler le nombre de lignes de l'historique. Noter que la dernière commande exécutée est toujours sauvegardée dans l'historique. |
home | Désigne le répertoire de localisation de celui qui invoque la commande. L'expansion de nom de fichier ~ se réfère à cette variable. |
ignoreeof | Le positionnement de cette variable permet au shell d'ignorer le caractère de fin de fichier quand il est généré depuis un terminal. Cela permet donc d'immuniser le shell d'une fin accidentelle déclenchée par la séquence ^D (lire <CTRL>-D). |
inputmode | [tcsh] Définit le mode en insertion (par défaut) ou en overwrite pour l'édition de la ligne de commande . |
mail | Indique le fichier dans lequel le shell contrôle l'arrivée de nouveaux messages. Si la première valeur spécifiée dans mail est numérique, elle surcharge l'intervalle de temps entre chaque vérification, fixé par défaut à 10 minutes. Si la variable spécifie différents fichiers, chacun d'eux sera scruté pour détecter l'arrivée de nouveaux messages. |
noclobber | Modifie la sémantique des commandes de redirections > et >> permettant ainsi d'éviter un effacement accidentel. L'utilisation de > renvoit une erreur si le fichier existe. Quand à >>, elle se réfère uniquement aux fichiers existants. |
noglob | Si cette variable est positionnée, elle inhibe la fonctionnalité d'expansion des noms de fichiers. Surtout utile dans les scripts shell. |
nonomatch | Si cette variable est positionnée, il n'y a pas d'erreurs lorsque le mécanisme d'expansion des noms de fichiers ne correspond pas à tous les fichiers existants. Dans ce cas le motif est retourné. |
notify | Si positionné alors permet au shell de notifier de manière asynchrone la completion des jobs. Le comportement par défaut spécifie de présenter la completion des jobs avant d'imprimer le prompt. |
path | Définit l'ensemble des chemins dans lesquels le shell recherche les commandes externes à exécuter. |
prompt | Définit l'invite de commandes en mode interactif. |
rmstar | [tcsh] Si positionné, permet de demander à l'utilisateur confirmation lorsqu'il tape la commande rm *. |
savehist | Si l'argument est numérique, spécifie le nombre de lignes sauvegardées dans ~/.history, quand l'utilisateur se déloggue. |
shell | Fichier dans lequel réside le shell. |
shlvl | [tcsh] Nombre de shell empilés, remis à 1 par un shell de login. |
status | Statut retourné par la dernière commande exécutée. |
time | Si cette variable est positionnée (valeur en secondes), alors toute commande dont la durée d'exécution dépasse cette valeur est suivie à sa terminaison de l'affichage de statistiques sur les temps utilisateur, système et réel consommés ainsi que le ratio temps utilisateur et temps système sur temps réel consommé. |
verbose |
Relations entre variables du shell et les variables d'environnement. En csh comme en tcsh certaines variables du shell et des variables d'environnement sont maintenues à des valeurs identiques par le shell. Ce sont les variables user et USER, group et GROUP, home et HOME, term et TERM, path et PATH, et enfin shlvl et SHLVL.
Les métacaractères jouent le rôle de classe de représentation des fichiers dans le contexte du répertoire courant si rien n'est précisé ou bien dans celui du répertoire explicitement nommé.
Le caractère ~ placé en première position désigne le répertoire personnel de l'utilisateur courant :
$ echo ~ /home/.sysop $ ls -l ~/elemntBase total 3 drwx------ 6 sysop gnu 512 Mar 14 14:43 Part1 drwx------ 4 sysop gnu 512 Mar 28 16:06 Part2 drwx------ 3 sysop gnu 512 Mar 20 22:20 Synthese
Le caractère * est substituable par n'importe quelle combinaison de 0 ou plusieurs caractères.
Exemple : Lister l'ensemble des fichiers commençant par le motif C-csh_n_tcsh du répertoire courant :
$ ls xb* xba xbc xbd xbe xbg xbf xbg xbh
Exemple : Lister les fichiers (non « cachés ») du répertoires courant :
$ > echo *
xaa xab xac xad xae xaf xagxba xbc xbd xbe xbg xbf xbg xbh xaa xab xac xad xae xaf xag
Les fichiers commençant par le caractère . ou fichiers « cachés » d'Unix™ [dot files] ne peuvent être remplacés par aucun caractère, i.e. le caractère « * » est inopérant.
Le caractère ? est substituable par un unique caractère quelconque.
Exemple : Lister les fichiers commençant par le motif C-csh_n_tcsh et dont le suffixe est réduit à deux caractères :
$ echo C-csh_n_tcsh.??
C-csh_n_tcsh.fo C-csh_n_tcsh.ps
Les caractères [] permettent une substitution par un caractère parmi l'ensemble dénoté par les crochets.
Exemple : Lister les fichiers « cachés » du répertoire $HOME de l'utilisateur courant, dont le second caractère est compris entre 'a' et 'e' (le premier étant le « . ») :
$ ls -d ~/.[a-e]* /home/pascal/.acrobat /home/pascal/.cshrc /home/pascal/.emacs.d /home/pascal/.acrorc /home/pascal/.cvsrc /home/pascal/.esd /home/pascal/.adobe /home/pascal/.deconnex /home/pascal/.esd_auth /home/pascal/.autosave /home/pascal/.dia /home/pascal/.exit.log /home/pascal/.bash_history /home/pascal/.emacs
Autre exemple, utilisation de la négation (extension tcsh) marqué par le caractère ^ : Lister les fichiers cachés du répertoire $HOME de l'utilisateur courant, dont le second caractère n'est ni '.', ni 'a', ni 'b', ni 'c', ni 'd' ni 'e' (le premier étant un '.') :
$ ls -d ~/.[^.a-e]* /home/pascal/.fetchmail.pid /home/pascal/.profile.rc /home/pascal/.fetchmailrc /home/pascal/.ressources /home/pascal/.fonts.cache-1 /home/pascal/.rhosts /home/pascal/.fr /home/pascal/.shadow_todo /home/pascal/.gkrellm /home/pascal/.shrc /home/pascal/.gnupg /home/pascal/.sversionrc /home/pascal/.gv /home/pascal/.tcsh_comp /home/pascal/.history /home/pascal/.themeinstaller /home/pascal/.ispell_francais /home/pascal/.user60.rdb /home/pascal/.login /home/pascal/.weblink /home/pascal/.logout /home/pascal/.xemacs /home/pascal/.mail_aliases /home/pascal/.xfigrc /home/pascal/.mailcap /home/pascal/.xinitrc /home/pascal/.mailrc /home/pascal/.xmms /home/pascal/.mgprc /home/pascal/.xsession /home/pascal/.mime.types /home/pascal/.xsession-errors /home/pascal/.mozilla /home/pascal/.xwm.msgs /home/pascal/.mutt
Les caractères { } permettent la substitution par un mot de l'énumération dénotée par les accolades.
Exemple : Lister les fichiers se terminant par les suffixes .xml et .pdf et .fo :
$ ls C-csh_n_tcsh.{xml,pdf,fo}
C-csh_n_tcsh.fo C-csh_n_tcsh.pdf C-csh_n_tcsh.xml
Quelques autres caractères spéciaux
Tableau 2. Autres caractères spéciaux du shell
| Caractère | Sémantique |
|---|---|
| ; | Séparateur de commande, i.e. opérateur de séquentialité. |
| & | Séparateur de commande qui place la commande qui le précède en arrière-plan, i.e. en exécution asynchrone. |
| \ | Quote le caractère qui le suit et notamment pour les caractères spéciaux, inhibe leur sémantique particulière. |
| $ | Accède au contenu de la variable. |
| ' | [quote] Quote le texte qui le suit jusqu'au ' fermant. |
| ` | [backquote] Considère le texte quoté comme une commande et la remplace par le résultat de son évaluation. |
| " | [double quote] Quote le texte qui le suit en interpolant les éventuelles variables qu'il contient. |
| ! | Substitution dans l'historique. |
| | | Tube [pipe]. |
| > et >> | Redirection de la sortie standard. |
| < et << | Redirection de l'entrée standard. |
| # | Marque le début d'un commentaire, i.e. pas d'expansion. |
| && | Et [And] logique. |
| || | Ou [Or] logique. |
Cette commande exécute le fichier (et ces éventuels arguments) qui lui est passé en argument dans le shell courant (i.e. pas de fork et donc modification (éventuelle) du shell courant).
$ source ~/.login
La commande setenv permet d'initialiser une variable d'environnement, i.e. une variable qui sera transmise à tous les processus fils du shell.
setenv OSTYPE FreeBSD setenv CPUTYPE k7 setenv PAGER less
La commande unsetenv permet de supprimer une variable d'environnement.
La commande set a deux fonctions :
l'initialisation d'une variable :
$ set path=( $path ~/bin )
Cette déclaration permet d'enrichir la variable path du répertoire bin de l'utilisateur.
la déclaration d'une option :
$ set ignoreeof
Cette option permet d'immuniser csh d'une destruction accidentelle. Il est normalement possible de clôre un terminal avec la séquence ^D (lire <CTRL>-D), mais si on positionne l'option ignoreeof la séquence précédente n'a plus d'effet.
La commande unset a évidement un effet symétrique. Elle permet donc de désarmer une option ou de supprimer une variable.
La portée de ces actions est limitée au shell courant contrairement à la commande précédente (c.f. Section 2.2, « setenv/unsetenv »).
Ce mécanisme permet de définir ou de redéfinir une commande. Exemple :
$ alias la /bin/ls -aoBG # definition de l'alias la $ alias rm /bin/rm -i # definition de l'alias rm $ alias # afficher les alias courants la (/bin/ls -aoBG) rm (/bin/rm -i)
En général, on place ces alias dans le fichier ~/.cshrc. Si on veut supprimer un alias on utilise la commande unalias comme suit :
$ unalias rm $ alias # afficher les alias courants la (/bin/ls -aoBG)
Pour ré-accéder à la commande masquée par son alias, comme dans l'exemple précédent où nous avons surchargé la commande classique rm, il suffit de :
Soit utiliser la commande par son nom absolu : /bin/rm.
Soit faire précéder la commande du caractère backslash (\), on tape donc toujours dans le cadre de l'exemple précédent : \rm
Cette commande permet de spécifier (si elle est suivie d'un argument valide) ou d'afficher la valeur du masque de création des objets i.e. des fichiers.
$ umask # affiche la valeur telle que prédéfinie dans ~/.cshrc 77 # autrement dir 0077 $ umask 0027 $ umask 27 # autrement dit 0027
Ce mécanisme a pour rôle de mémoriser les n dernières commandes entrées, ce nombre étant un paramètre réglable. Cela permet de visualiser, d'éditer et/ou exécuter à nouveau les commandes mémorisées. La commande suivante permet d'activer l'historisation des commandes, elle signifie que les 512 dernières commandes seront mémorisées :
$ set history = 512
La commande suivante permet en plus de sauvegarder les m dernières commandes dans ~/.history au logout. Il est évident que m est au plus égale à n. Ici, nous ne retenons que les 256 dernières commandes :
$ set savehist = 256
La commande history permet d'afficher les commandes dans l'ordre de leur mémorisation.
$ history ... 80 8:57 cp csh/Makefile Makefile.gen 81 9:03 more Makefile.gen 82 9:06 sed -e 's/SRCNAME=C-csh_n_tcsh/SRCNAME=/' Makefile.gen > Makefile 83 9:07 xemacs createinf.sh 84 9:09 which mkdir 85 9:09 rm -rf html/ && make check && make html 86 9:10 ls -l csh/ 87 9:12 echo $$
Pour relancer une commande, il suffit de l'appeler par son numéro (relativement à l'historique) en la préfixant par le caractère !. Par exemple, si on veut relancer la commande 84, il suffit de faire :
$ !84 which mkdir /bin/mkdir
Tableau 3. Quelques commandes de manipulation de l'historique
| Expression | Sémantique |
|---|---|
| !! | Répéter la dernière commande. |
| !n | Répéter la commande numéro n. |
| !-n | Répéter la nième précédent la dernière de l'historique, i.e. !-2 : avant dernière commande. |
| !texte | Répéter la dernière commande commençant par texte. |
| !?texte | Répéter la dernière commande contenant texte. |
| !:n | Répéter le nième mot de la dernière commande. |
| !$ | Répéter le dernier mot de la dernière commande. |
| !* | Répéter tous les arguments de la dernière commande. |
| ^old^new | Répéter la dernière commande en commençant par remplacer la première occurence de old par new. |
| !n:s^old^new | Répéter la nième commande en commençant par remplacer la première occurence de old par new. |
| !n:gs^old^new | Répéter la nième commande en commençant par remplacer toutes les occurences de old par new (substitution globale). |
Pour terminer, il peut être intéressant de positionner l'alias suivant dans son ~/.cshrc.
alias h 'history -r \!* | less'
En csh la completion est activée par le positionnement de la variable d'environnement filec (c.f. « Section 1.4, « Variables prédéfinies et d'environnement » »). Ce mécanisme permet, selon le contexte, de compléter les noms de fichiers ou d'utilisateurs à partir de la saisie d'un préfixe suivi de la frappe du caractère « ESC ». Le contexte par défaut étant celui de fichiers.
Supposons, par exemple, que le contenu du répertoire courant soit le suivant :
_merge.pl check.pl fdate.sh mytest.pl _pidof.pl crlf.pl gen-meta-index.pl replace_header_html.pl _split.pl extract.pl idle.pl rotate.pl _test.pl extract_piste.sh logfile-1.2.pl rsync.pl bidir.pl fcomp.sh mylock.sh
Alors la séquence suivante : $ ls l<ESC> est résolue en (seule correspondance possible) : $ ls logfile-1.2.pl
Tandis que la séquence ci-contre : $ ls ext<ESC> est résolue partiellement en : $ ls extract suivit de l'émission d'un bip qui signale que cette expansion est incomplète puisque deux fichiers correspondent au préfixe saisi. La commande précédente suivie du <CTRL>-D permet d'obtenir l'ensemble des réponses potentielles :
$ ls extract<CTRL>-D extract.pl* extract_piste.sh* $ ls extract
La saisie d'un seul caractère supplémentaire permet dans ce dernier cas de lever l'ambiguïté.
L'utilisation du bip (sonnerie du terminal) pour signaler des erreurs ou des correspondances potentielles peut être désactivée par le positionnement de la variable nobeep. Enfin, il est possible de limiter les correspondances potentielles à la completion en positionnant la variable fignore. Dans l'exemple suivant, on exclut des correspondances possibles les fichiers suffixés en .o, .out et *~.
$ set fignore = (.o .out *~)
Contexte utilisateur : le mécanisme de completion peut être utilisé pour compléter les noms d'utilisateurs. Il faut utiliser le préfixe ~ (il change le contexte de la completion) :
$ cd ~sys<ESC> $ cd ~sysop
Supposons qu'un utilisateur ait souvent besoin de se rendre alternativement dans le répertoire /home/cvsroot/ et dans son propre répertoire ~/elemntBase, il peut alors :
pour se rendre en /home/cvsroot/C-network/, taper :
$ cd /home/cvsroot/C-network
et pour se rendre en ~/elemntBase, taper :
$ cd ~/elemntBase
Mais, cet utilisateur peut aussi se simplifier la vie en positionnant la variable cdpath, ainsi :
$ set cdpath = ( /home/cvsroot ~ )
Ainsi, il peut se contenter de :
taper dans le premier cas :
$ cd C-network /home/cvsroot/C-network
et dans le second :
$ cd elemntBase ~/elemntBase
Une pile est une structure de données qui permet de mémoriser des entrées et dont la stratégie d'accès est de type LIFO (Last In, First Out), i.e. on accède uniquement au sommet de la pile.
La pile des répertoires est gérée par les trois primitives suivantes :
La commande pushd qui permet de changer de répertoire (comme cd), en conservant l'ancien répertoire dans la pile (il est empilé).
La commande popd qui permet de changer de répertoire (comme cd), en dépilant le sommet de la pile.
La commande dirs qui permet d'afficher le contenu de la pile.
L'exemple suivant permet d'en comprendre le fonctionnement :
$ pwd/usr/home/.sysop/elemntBase/part4 $ pushd /usr/local/etc
/usr/local/etc ~/elemntBase/part4 $ pwd
/usr/local/etc $ popd
~/elemntBase/part4 $ pwd
/usr/home/.sysop/elemntBase/part4 $ pushd /usr/local/etc /usr/local/etc ~/elemntBase/part4 $ pwd /usr/local/etc $ dirs -v
0 /usr/local/etc 1 ~/elemntBase/part4 $ more =1/domains.txt
http://167.216.142.116 http://193.128.61.168 http://193.210.156.114 ... encore plein de lignes...
Un processus est l'instance d'un programme en exécution. C'est une structure de données qui contient du code statique, des données statiques et dynamiques et un environnement d'exécution. Un processus possède un cycle de vie marqué par des états comme l'exécution (runnable), la suspension, l'attente, le sommeil, l'état zombie... Pour se voir allouer des tranches de temps (time slice) d'exécution sur le CPU, un processus doit être dans l'état exécutable.
Chaque programme démarré par le shell nécessite la création d'un nouveau processus, on a ainsi une arborescence de processus, puisqu'une nouvelle instance ne possède qu'un seul parent. L'utilitaire ps permet d'obtenir un instantané des processus en cours
$ > ps PIDTT
STAT
TIME
COMMAND
13123 p0- I 0:03.58 xdiary 13124 p0- I 0:00.31 xdalarm -cmdPipeId /var/tmp/tmp.0.B2ekTh 15124 p0 Is 0:00.28 -tcsh (tcsh) 16108 p0 S+ 0:00.10 /usr/local/bin/wget -NSc ftp://ftp.openbsd.org/ 15185 p1 Ss 0:00.38 -tcsh (tcsh) 15263 p1 S 0:43.71 xemacs C-csh_n_tcsh.xml (xemacs-21.1.14) 16109 p1 R+ 0:00.00 ps 14204 p2 Is+ 0:00.09 ssh -p 3322 -v pascal@Turing.corto.home 15534 p4 I+ 0:00.28 mutt 52875 p4 Is 0:00.25 -tcsh (tcsh) 50861 p5 Is 0:00.25 -tcsh (tcsh)
| Process Identifier, identifiant (unique) du processus. |
| TTy device, terminal d'exécution. |
| STATus, état du processus |
| TIME consumed, temps CPU consommé. |
| La commande exécutée. |
Le système identifie chaque processus au moyen d'un entier appelé pid. Dans l'exemple précédent, la dernière ligne identifie le processus 50861 qui est un shell (tcsh) dans l'état idle, i.e. en sommeil depuis plus de 20 secondes, sur le terminal /dev/ttyp5.
La consultation du man 1 ps permet d'obtenir une explication complète de la commande. Je rappelle ici la sémantique BSD associée au premier caractère de la colonne STAT :
Tableau 4. Sens des éléments de la colonne STAT
| Caractère | Sémantique |
|---|---|
| D | Processus en attente d'une E/S disque. |
| I | Processus en sommeil depuis plus de 20 secondes. |
| R | Processus en exécution sur le CPU. |
| S | Processus en sommeil depuis moins de 20 secondes. |
| T | Processus suspendu (stoppé) |
| Z | Processus Zombie |
Des caractères additionnels permettent d'avoir des informations supplémentaires, citons le + qui indique un processus d'avant plan (interactif [foreground]) parmi le groupe de processus contrôlé par un terminal.
La commande ps l (c.f. exemple suivant) permet d'obtenir plus de détails sur les processus. On y trouve les paramètres suivants :
l'uid : propriétaire du processus,
le pid : identifiant du processus,
le ppid : identifiant du père du processus,
le cpu : estimation du temps CPU consommé,
le pri : i.e. priorité d'ordonnancement,
le nice : priorité assignée par nice ; la modification de cette valeur permet d'influer sur l'algorithme d'ordonnancement [scheduling],
le vsz : donne la taille de la mémoire virtuelle utilisée (exprimée en kilo-octet),
le rss : taille de la mémoire réelle utilisée (exprimée en kilo-octet).
le wchan : le canal d'attente, i.e. l'adresse d'une structure de données identifiant la ressource ou l'évènement pour lequel le processus est en attente,
le state : état du processus parmi (R, S, I, Z ...),
le tt : le terminal associé au processus,
le time : temps cpu accumulé (utilisateur et système),
enfin la commande elle-même.
$ ps l UID PID PPID CPU PRI NI VSZ RSS WCHAN STAT TT TIME COMMAND 666 13123 1 0 2 0 6424 5212 poll S p0- 0:07.40 xdiary 666 13124 13123 0 2 0 4956 3132 poll S p0- 0:00.76 xdalarm -cmdPi 666 15185 15182 0 18 0 2048 1684 pause Ss p1 0:00.57 -tcsh (tcsh) 666 20568 15185 0 2 0 13820 12388 poll S p1 0:05.60 xemacs C-csh_n 666 20596 15185 0 28 0 420 208 - R+ p1 0:00.00 ps -l 666 14204 14203 0 2 0 2080 1500 select Ss+ p2 0:00.19 ssh -p 3322 -v 666 17975 17972 0 3 0 2048 1676 ttyin Is+ p3 0:00.22 -tcsh (tcsh) 666 19717 52875 0 2 0 3868 2932 poll S+ p4 0:00.42 mutt 666 52875 52872 0 18 0 2044 1664 pause Is p4 0:00.25 -tcsh (tcsh) 666 50861 50858 0 18 0 2044 1672 pause Is p5 0:00.26 -tcsh (tcsh)
L'invocation d'un programme déclenche un nouveau processus chargé de son exécution et pendant ce temps, le shell (père du processus) est suspendu jusqu'à la terminaison de ce processus. On parle alors d'éxecution interactive (ou en avant-plan [foreground]). Il est évidement possible d'exécuter un processus de manière asynchrone [background], i.e. de permettre au shell d'exécuter de nouvelles commandes immédiatement. Il suffit pour se faire de postfixer la commande à exécuter de manière asynchrone par le caractère « ampersand » : &. Voici un exemple (noter le numéro du processus : 20713) :
$ fetchmail & [2] 20713
csh a introduit la notion de suspension d'un processus interactif par la commande ^Z (lire <CTRL>-Z). La reprise peut se faire de manière asynchrone (arrière plan) par la commande bg ou de manière interactive (avant plan) avec la commande symétrique fg.
Pour finir, signalons la commande top qui permet d'avoir des informations en temps réel sur les processus (rafraîchissement toutes les 2 secondes). En voici un exemple tronqué :
last pid: 21084; load averages: 0.08, 0.03, 0.01 up 15+03:11:37 23:13:33 56 processes: 1 running, 54 sleeping, 1 stopped CPU states: 3.5% user, 0.0% nice, 4.7% system, 1.2% interrupt, 90.7% idle Mem: 365M Active, 430M Inact, 124M Wired, 48M Cache, 112M Buf, 37M Free Swap: 4096M Total, 48K Used, 4096M Free PID USERNAME PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND 50627 root 2 0 143M 141M select 80:43 1.90% 1.90% XFree86 50670 pascal 2 0 7960K 5000K poll 100:08 1.86% 1.86% gkrellm 15182 pascal 2 0 6660K 5488K select 0:03 0.78% 0.78% Eterm 15164 pascal 2 0 15416K 9872K poll 34:27 0.05% 0.05% xmms 51005 pascal 2 0 126M 118M poll 20:16 0.00% 0.00% mozilla-bin 50675 pascal 2 0 2052K 1452K select 8:44 0.00% 0.00% wmmatrix 208 root 2 0 3940K 2992K select 2:41 0.00% 0.00% cupsd 50674 pascal 10 0 2104K 1544K nanslp 2:04 0.00% 0.00% wmitime 50647 pascal 2 0 5484K 3996K select 1:51 0.00% 0.00% wmaker 15168 pascal 10 0 2344K 1684K nanslp 1:14 0.00% 0.00% wmmixer 20568 pascal 2 0 14992K 13912K poll 0:40 0.00% 0.00% xemacs-21.1.14 312 nobody 10 0 2288K 1296K nanslp 0:29 0.00% 0.00% cups-polld 50727 pascal 2 0 2844K 2284K poll 0:16 0.00% 0.00% xscreensaver 274 mysql 2 11 27016K 3632K poll 0:09 0.00% 0.00% mysqld 50721 pascal 2 0 1780K 1076K select 0:09 0.00% 0.00% root-tail 13123 pascal 2 0 6424K 4984K poll 0:08 0.00% 0.00% xdiary 181 root 2 0 2204K 988K select 0:06 0.00% 0.00% master 50858 pascal 2 0 7032K 5772K select 0:06 0.00% 0.00% Eterm 52872 pascal 2 0 5564K 4312K select 0:05 0.00% 0.00% Eterm 88 root 2 0 944K 556K select 0:04 0.00% 0.00% syslogd 96 root 10 0 988K 480K nanslp 0:03 0.00% 0.00% cron 50713 pascal 2 0 3236K 1524K select 0:03 0.00% 0.00% fetchmail 183 postfix 2 0 2260K 1052K select 0:03 0.00% 0.00% qmgr 50662 pascal 2 0 1944K 1240K select 0:02 0.00% 0.00% ssh-agent 16122 root 2 0 15036K 8456K select 0:02 0.00% 0.00% Xvfb 52911 pascal 2 0 1220K 760K select 0:01 0.00% 0.00% esd
Les signaux sont une forme limitée de communication inter-processus. Ils permettent de prévenir les processus de l'occurence de certains évènements. Il est possible d'envoyer des signaux à des processus interactifs à partir du clavier. La commande suivante permet de connaître les associations clés/signaux :
$ stty -a
speed 38400 baud; 50 rows; 132 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr ixon -ixoff -ixany imaxbel -ignbrk
brkint -inpck ignpar -parmrk
oflags: opost onlcr -ocrnl -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd -hupcl -clocal -cstopb -crtscts
-dsrflow -dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
eol2 = <undef>; erase = ^?; erase2 = ^@; intr = ^C; kill = ^U;
lnext = ^V; min = 1; quit = ^\; reprint = ^R; start = ^Q;
status = ^T; stop = ^S; susp = ^Z; time = 0; werase = ^W;
Ainsi, la séquence <CTRL>-C (^C) permet d'envoyer le signal de terminaison (INT signal), la séquence <CTRL>-\ (^\) permet d'envoyer un autre signal de terminaison (QUIT), la séquence <CTRL>-Z (^Z) permet d'envoyer le signal de suspension (TSTP). Par défaut, les deux premiers signaux (INT et QUIT) termine le processus, tandis que le troisième ne fait que suspendre l'éxecution, i.e. elle peut donc être reprise. Ce comportement par défaut peut cependant être redéfini au sein d'un processus.
Sur une architecture 4.4BSD (FreeBSD, NetBSD, OpenBSD) on trouve 31 signaux. La commande, improprement nommée kill (man 1 kill) permet d'envoyer des signaux à un processus. Sa syntaxe est la suivante : kill <signal> <pus>, où <signal> est le signal envoyé au processus de numéro <pus>
La liste des signaux délivrable par la commande kill peut être obtenue de la manière suivante :
$ kill -l HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2
Parmi ces signaux, deux ne peuvent être ni ignorés, ni détournés. Il s'agit du KILL (terminaison) et du STOP (suspension ou stop) (à ne pas confondre avec le TSTP vu précédemment).
Cette notion inventée par la branche BSD d'Unix™ et introduite par csh est désormais disponible sur toutes les distributions Unix™ libres.
Un job est soit un processus, soit un groupe de processus lancé par le shell. Un job peut être suspendu, redémarré, terminé, executé interactivement ou de manière asynchrone. Le shell sait gérer plusieurs jobs simultanément, toutefois à un instant donné seul un job peut avoir accès au terminal. Les jobs sont intéressants dès que les processus qu'ils contrôlent ont une durée de vie de quelques secondes. Analysons la séquence suivante :
$ su toorPassword: # id uid=0(root) gid=0(wheel) groups=0(wheel) # suspend
Suspended $ jobs
[1] - Running xemacs C-csh_n_tcsh.xml [2] + Suspended su toor $ du -s -h /usr &
[3] 21136 $ ls3.7G /usr
[3] Exit 1 du -s -h /usr
$ ls /usr C-csh_n_tcsh.xml Makefile _mystyle.xsl images my_style.xsl CVS _mystyle.css html my_print.dsl $ stty tostop
$ du -s -h /usr & ... $ jobs [1] Running xemacs C-csh_n_tcsh.xml [2] - Suspended su toor [3] + Suspended (tty output) du -s -h /usr
$ %3
du -s -h /usr 3.7G /usr $ jobs [1] - Running xemacs C-csh_n_tcsh.xml [2] + Suspended su toor $ %2 # exit
$ jobs [1] + Running xemacs C-csh_n_tcsh.xml
| Changement d'identité utilisateur. |
| Suspension du processus et restauration de l'identité précédente. |
| Liste des jobs en cours; |
| Lancement d'une nouvelle commande, i.e. un processus de manière asynchrone, celui ci écrira son éventuel résultat sur la sortie standard, sans se préoccuper de ce qu'il peut se passer ! |
| Le résultat de la commande du survient au moment où l'utilisateur tape sa commande ls et pertube donc son affichage. |
| Terminaison du processus. La commande ls s'affiche alors. |
| Pour éviter le mélange précédent, nous bloquons l'écriture du résultat de la commande sur le terminal. |
| Le comportement du processus change, l'utilisateur est informé (variable notify de csh, c.f. « Section 1.4, « Variables prédéfinies et d'environnement » ») que le job 3 est prêt à imprimer son résultat (il est suspendu jusqu'à ce qu'il soit autorisé à la faire). |
| On rappelle le job 3, ce qui lui permet d'afficher son résultat. Un job asynchrone qui veut lire sur l'entrée standard alors que ce canal n'a pas été redirigé est toujours suspendu. Il faut le relancer de manière interactive pour qu'il puisse collecter ses données sur l'entrée standard. |
| On rappelle le job 2 et on le termine explicitement par un exit. Il reste alors un seul job en exécution asynchrone. |
La liste des jobs en cours est donné par la commande jobs.
Le caractère % en première position dénote un job.
Le tableau suivant (c.f. « Tableau 5, « référencement des jobs » ») récapitule les différentes manières de référencer un job.
Tableau 5. référencement des jobs
| Expression | Sémantique |
|---|---|
| %n | job numéro n. |
| %str | job commençant par la chaine str. |
| %?str | job contenant la chaine str. |
Le tableau suivant (c.f. « Tableau 6, « Commandes contrôlant les jobs » ») donne les commandes de contrôle d'un job.
Tableau 6. Commandes contrôlant les jobs
| Expression | Sémantique |
|---|---|
| bg [name] | Place le job name en exécution asynchrone. Si l'argument name n'est pas précisé, la commande s'applique au job courant. |
| name & | Place le job name en exécution asynchrone. |
| fg [name] | Place le job name en exécution interactive. Si l'argument name n'est pas précisé, la commande s'applique au job courant. |
| name | Place le job name en exécution interactive. |
| stop name | Suspend le job name. |
Enfin, la commande kill permet aussi d'envoyer des signaux aux jobs, en utilisant le même référencement des jobs qu'en « Tableau 5, « référencement des jobs » ». Ainsi, la commande suivante met fin au job 1 :
$ kill -TERM %1
En csh, comme en tcsh les processus asynchrones ne sont pas affectés par un logout puisqu'il n'y a pas d'envoi du signal HUP à l'exécution du logout.
Corollaire : pas besoin de la commande nohup des autres shells (tel GNU/Bash).
Cette commande a pour objet de définir des limites à la consommation des ressources du système par les processus. Il s'agit d'un intervalle définit par une borne haute (hard limits : qui ne peut être modifiée qu'à la baisse, sauf par le super-utilisateur et une borne basse (current limits : qui peut être accrue jusqu'aux valeurs de la borne haute).
$ limit # affichage des limites courantes cputime unlimited filesize unlimited datasize 262144 kbytes stacksize 262144 kbytes coredumpsize 0 kbytes memoryuse unlimited vmemoryuse unlimited descriptors 2048 memorylocked unlimited maxproc 1024 sbsize unlimited $ limit coredumpsize 1024 # augmenter la limite basse d'un fichier core à 1024k $ limit maxproc 2048 # augmenter le nb max de proc concurrents limit: maxproc: Can't set limit (Operation not permitted) $ limit maxproc 512 # augmenter le nb max de proc concurrents (lim. cour.) $ limit -h maxproc 784 # augmenter le nb max de proc concurrents (lim. hautes) $ limit # affichage des limites courantes cputime unlimited filesize unlimited datasize 262144 kbytes stacksize 262144 kbytes coredumpsize 1024 kbytes memoryuse unlimited vmemoryuse unlimited descriptors 2048 memorylocked unlimited maxproc 512 sbsize unlimited $limit -h # affichage des limites hautes cputime unlimited filesize unlimited datasize 262144 kbytes stacksize 262144 kbytes coredumpsize unlimited memoryuse unlimited vmemoryuse unlimited descriptors 2048 memorylocked unlimited maxproc 784 sbsize unlimited
Rapellons que, sous Unix™ en général et sous BSD en particulier, il existe trois canaux d'E/S standard :
L'entrée standard [stdin] associée au fd [file descriptor] 0 liée traditionnellement au clavier.
La sortie standard [stdout] associée au fd 1, liée traditionnellement à l'écran du terminal.
La sortie standard d'erreur [stderr] associée au fd 2, liée traditionnellement à l'écran du terminal.
Formellement, un descripteur de fichier est un entier non signé utilisé par les processus pour référencer les canaux d'E/S.
La puissance et la flexibilité du concept des canaux standards d'E/S tient essentiellement au fait que le shell peut rediriger ces canaux aussi bien sur des fichiers, que l'écran ou le clavier.
Tableau 7. Redirections
| Symbole | Sémantique |
|---|---|
| > <fnom> | La sortie standard est redirigée dans le fichier <fnom>. S'il existait, son contenu est perdu et sinon il est créé. |
| >> <fnom> | La sortie standard est redirigée dans le fichier <fnom>, ouvert en mode ajout s'il existait, sinon il est créé. |
| >& <fnom> | La sortie d'erreur est redirigée dans le fichier <fnom>. S'il existait, son contenu est perdu et sinon il est créé. |
| >>& <fnom> | La sortie d'erreur est redirigée dans le fichier <fnom>, ouvert en mode ajout s'il existait, sinon il est créé. |
| < <fnom> | L'entrée standard est le fichier <fnom>. |
| << <mot> | Lit les entrées du shell jusqu'à une ligne commençant (et contenant uniquement) le mot <mot> qui agit comme un marqueur de fin. |
Le positionnement de la variable interne noclobber, permet d'éviter l'écrasement des fichiers existants dans le cas de l'utilisation des commandes de redirection > et >&. De plus les commandes >> et >>& ne peuvent être exécutées que sur des fichiers existants.
Enfin, la sémantique initiale des commandes de redirection (après activation de noclobber) peut être explicitement restituée en utilisant le symbole !. Ainsi, les commandes >!, >>!, >&! et >>&! ont un comportement identique à leurs homologues du tableau précédent (i.e. sans le !, c.f. « Tableau 7, « Redirections » »).
EXEMPLES :
$ cat > file.txt << fin_de_saisie
>> première ligne
>> puis une 2e
>> Encore une autre !
>> C'est pas fini ...
>> fin_de_saisie
$ ll file.txt
-rw------- 1 pascal gnu - 65 Aug 1 15:58 file.txt
$ cat < file.txt # équivalent à cat file.txt
première ligne
puis une 2e
Encore une autre !
C'est pas fini ...
$ ( find /home -name "*~" -print > fout ) >& ferr
# séparer les sorties standard (> fout) et d'erreur (>& ferr)
$ cat fout # les résultats
/home/pascal/enseignement/NeoTechIII/V2L-PRAI/CS2-csh/toto.sh~
/home/pascal/enseignement/NeoTechIII/V2L-PRAI/Progr-V2L/Progr-V2L.xml~
/home/miji/work/these/annexes/annexes.sxw~
/home/miji/work/these/partie1/part_legende/legendes.sxw~
/home/hosts/corto-home/turing/postfix/main.cf~
/home/hosts/corto-home/euler/ulocal-etc/flexbackup/flexbackup.conf~
/home/hosts/corto-home/euler/ulocal-etc/tripwire/twpol.txt~
/home/hosts/corto-home/euler/etc/ssh/sshd_config~
/home/hosts/corto-home/tux/etc/apache/httpd.conf~
/home/hosts/corto-home/tux/etc/apache-ssl/httpd.conf~
$ cat ferr # les erreurs
find: /home/miji/.ssh: Permission denied
find: /home/miji/work/lit_reu/Dayot: Permission denied
find: /home/miji/Choices: Permission denied
find: /home/miji/pdf: Permission denied
find: /home/miji/tmp: Permission denied
find: /home/miji/.Eterm: Permission denied
find: /home/miji/.mozilla: Permission denied
find: /home/miji/.mutt: Permission denied
find: /home/miji/.netscape: Permission denied
find: /home/miji/.prefs: Permission denied
find: /home/miji/.vnc: Permission denied
find: /home/miji/.Gabber: Permission denied
find: /home/miji/.wmakerconf: Permission denied
Le mécanisme de pipeline consiste à rediriger la sortie d'une commande vers l'entrée d'une autre. D'un point de vue syntaxique nous avons la structure suivante :
<commandA> | <commandB>
Exemple 4. Utilisation du mécanisme de pipeline
$ ls -l | sort -k 5n
La sortie de la commande ls -l est redirigée vers l'entrée de la commande sort -k 5n.
Enfin, en postfixant au tube ('|' ou encore pipe) l'ampersand (&), il est possible de combiner les sorties standard et d'erreur vers l'entrée de la commande qui suit (le tube).
<commandA> |& <commandB>
Ces structures algorithmiques sont utilisées dans les scripts shells. Pour rédiger un script shell (ici, en tcsh), il faut :
Créer le fichier avec un éditeur de texte (sample.sh). La première ligne doit commencer avec le prologue [shebang] : #!/bin/tcsh.
Lui attribuer la permission d'exécution sur le fichier créé (chmod +x sample.sh).
Enfin, pour l'exécuter il suffit de taper le nom du fichier, puisque c'est désormais une nouvelle commande (si on est dans le répertoire courant de cette commande, il suffit de taper ./sample.sh).
Nous donnons dans ce qui suit, quelques exemples de scripts shells (csh).
Cette structure permet l'exécution conditionnelle d'une instruction. Voici sa syntaxe :
if ( <condition> ) then <liste instructions> else if ( <condition> ) then <liste instructions> else if ( <condition> ) then <liste instructions> else <liste instructions> endif
Exemple 5. Utilisation du if
#!/bin/csh
# /home/pascal/bin/fcomp.sh
#
# but : comparer deux fichiers
#
# [Sept. 2002]
if ( ${#argv} != 2 ) then
echo "usage : $0 file1 file2"
echo "compare deux fichiers file1 et file2 et dit s'ils sont identiques ou \
differents."
exit -1
endif
cmp $argv[1] $argv[2] >& /dev/null
set ret = $?
if ( $ret == 0 ) then
echo "Les fichiers $argv[1] et $argv[2] sont identiques."
else if ( $ret == 1 ) then
echo "Les fichiers $argv[1] et $argv[2] sont differents."
else
echo "Une erreur est survenue !"
endif
exit $ret
Exemple 6. Résultat du code de Exemple 5, « Utilisation du if »
$ ~/bin/fcomp.sh usage : /home/pascal/bin/fcomp.sh file1 file2 compare deux fichiers file1 et file2 et dit s'il sont identiques ou differents. $ ~/bin/fcomp.sh ~/bin/fdate.sh ~/bin/fcomp.sh Les fichiers /home/pascal/bin/fdate.sh et /home/pascal/bin/fcomp.sh sont differe nts. $ ~/bin/fcomp.sh ~/bin/fdate.sh /etc/shadow Une erreur est survenue !
Cette structure permet l'exécution conditionnelle d'une instruction.
switch ( <variable> )
case motif1 :
<liste instructions>
breaksw
case motif2 :
case motif3 :
<liste instructions>
breaksw
case motif4 :
<liste instructions>
case motif5 :
<liste instructions>
default:
<liste instructions>
endsw
Exemple 7. Utilisation du switch
#!/bin/csh
# /home/pascal/bin/fdate.sh
#
# but : conversion date en francais
#
# [Sept. 2002]
set res=`date`
# Traiter le jour
switch ( $res[1] )
case Mon :
set day=Lun
breaksw
case Tue :
set day=Mar
breaksw
case Wed :
set day=Mer
breaksw
case Thu :
set day=Jeu
breaksw
case Fri :
set day=Ven
breaksw
case Sat :
set day=Sam
breaksw
case Sun :
set day=Dim
breaksw
endsw
# Traiter le mois
switch ( $res[2] )
case Feb :
set mon=Fev
breaksw
case Apr :
set mon=Avr
breaksw
case May :
set mon=Mai
breaksw
case Jun :
set mon=Juin
breaksw
case Jul :
set mon=Juil
breaksw
case Aug :
set mon=Aou
breaksw
case Jan :
case Sep :
case Oct :
case Nov :
case Dec :
set mon=$res[2]
breaksw
endsw
# Afficher le resultat
echo "$day $res[3] $mon $res[6], $res[4] [$res[5]]"
Exemple 8. Résultat du code de Exemple 7, « Utilisation du switch »
$ fdate.sh Sam 12 Avr 2003, 21:20:45 [RET]
Il s'agit de l'instruction standard qui permet d'exécuter le corps de la boucle tant que la condition d'entrée est vérifiée (valeur évaluée à vrai).
while ( <condition> ) <corps_de_boucle> end
Exemple 9. Utilisation du while
#!/bin/csh # ~/bin/test.sh set ind=1 while ( $ind < 11 ) @ indcar = $ind * $ind echo $ind " " $indcar @ ind++ end
Exemple 10. Résultat du code de Exemple 9, « Utilisation du while »
$ ~/bin/test.sh 1 1 2 4 3 9 4 16 5 25 6 36 7 49 8 64 9 81 10 100
Cette instruction permet de répéter un nombre entier de fois une même commande.
repeat <nombre_de_fois> <commande>
Cette instruction permet de traiter en séquence tous les éléments d'une liste.
foreach <variable> ( <liste_de_valeur> ) <corps_de_boucle> end
Exemple 12. Utilisation du foreach
#!/bin/csh # ~/bin/test.sh foreach i ( 1 2 3 4 5 6 7 8 9 ) @ m = $i * 2 echo -n " $m" end echo
Exemple 13. Résultat du code de Exemple 12, « Utilisation du foreach »
$ ~/bin/test.sh 2 4 6 8 10 12 14 16 18 $
Ce sont les variables que les utilisateurs peuvent définir. Le shell étant un langage interprété non typé, aucune déclaration n'est nécessaire et la même variable peut contenir tour à tour une chaîne de caractères, un entier, ou un vecteur (tableau d'éléments de type chaîne de caractères ou entier, indexé par des entiers, commençant à 1).
Affectation. Cette opération permet d'associer un contenu à une variable (le contenant). En csh comme en tcsh, l'affectation se fait en utilisant la commande interne set de la manière suivante :
EXEMPLE :
$ set myvar1 = 10
$ set myvar2 = "chaine de caractère"
$
Accès au contenu. L'accès au contenu de la variable se fait en préfixant le nom de la variable par le symbole $.
EXEMPLE (SUITE) :
$ echo $myvar1
10
$ echo $myvar2
chaine de caractère
$ echo myvar1 # omission du méta-caractère $
myvar1 # echo affiche le mot myvar1
On peut aussi encadrer la variable par les symboles { et } avant de la préfixer par le symbole $ :
EXEMPLE (SUITE) :
$ set si = "pas "
$ echo "c'est vraiment $sidrôle"
sidrôle: Undefined variable. # le $ porte ici sur le mot sidrôle et non sur si
$ echo "c'est vraiment ${si}drôle"
c'est vraiment pas drôle
$
L'accès à une variable non définie produit (sauf rares exceptions) une erreur (en csh, comme en tcsh).
Effacer une variable. Cette opération permet de libérer la case mémoire occupée par la variable. Cela se fait en csh comme en tcsh, en utilisant la commande interne unset de la manière suivante :
EXEMPLE (SUITE) :
$ echo $myvar1
10
$ unset myvar1
$ echo $myvar1
myvar1: Undefined variable.
$
Variable de type vecteur. Voici un exemple :
CODE : #!/bin/csh # ~/bin/testvect.sh set vect = ( 2 -2 4 -4 6 -6 8 -8 10 -10 ) # afficher les elements du vecteur vect, element par element set i = 1 set sum = 0 echo " - Affichage element par element" while ( $i <= ${#vect} ) echo '$vect[' $i '] = ' $vect[$i] @ sum = $sum + $vect[$i] @ i++ end echo " - Somme des elements = " $sum # acc賠par tranche set j = 5 echo "Voici le vecteur vect (${#vect} elements) : " $vect[1-] echo "Voici les $j premiers elements du vecteur : " $vect[-$j] echo "Voici les derniers elements ࠰artir du $j e : " $vect[$j-] # fin du script EXEMPLE : $ ./testvect.sh - Affichage élément par élément $vect[ 1 ] = 2 $vect[ 2 ] = -2 $vect[ 3 ] = 4 $vect[ 4 ] = -4 $vect[ 5 ] = 6 $vect[ 6 ] = -6 $vect[ 7 ] = 8 $vect[ 8 ] = -8 $vect[ 9 ] = 10 $vect[ 10 ] = -10 - Somme des elements = 0 Voici le vecteur vect (10 éléments) : 2 -2 4 -4 6 -6 8 -8 10 -10 Voici les 5 premiers éléments du vecteur : 2 -2 4 -4 6 Voici les derniers éléments à partir du 5 e : 6 -6 8 -8 10 -10 $
Modificateurs de variables. Les modificateurs [modifiers] suivants peuvent être appliqués aux variables. On travaillera avec l'exemple (un vecteur) suivant :
$ set mypath = ( /usr/local/src/foo.c /usr/src/bar.cc ) # un vecteur de path
Tableau 8. Clé de modification
| Clé | Sémantique | Exemple | |||
|---|---|---|---|---|---|
|
| $ echo $mypath:h /usr/local/src /usr/src/bar.cc $ echo $mypath:gh /usr/local/src /usr/src | |||
|
| $ echo $mypath:t foo.c /usr/src/bar.cc $ echo $mypath:gt foo.c bar.cc | |||
| supprime l'extension en fin de variable. | $ echo $mypath:r /usr/local/src/foo /usr/src/bar.cc $ echo $mypath:gr /usr/local/src/foo /usr/src/bar | |||
| donne l'extension correspondant à la fin de variable. | $ echo $mypath:e c /usr/src/bar.cc $ echo $mypath:ge c cc | |||
| quote la variable pour éviter tout mécanisme de substitution. | ||||
|
|
Mécanismes de substitution.
Tableau 9. Clé de substitution
| Clé | Sémantique |
|---|---|
$?<name> = ${?<name>} | Renvoit 1 si la variable est définie, 0 sinon. |
$?0 | Renvoit 1 si $0 est définie, 0 sinon. |
$$ | Substituée par le pid du shell parent. |
$! | Substituée par le pid du dernier processus asynchrone lancé par le shell parent. |
$< | Substituée par une ligne de l'entrée standard. |
$ set v = toto
$ echo ${?v} # renvoit 1 puisque la variable v est définie
1
$ echo $u
u: Undefined variable.
$ echo ${?u} # moyen commode pour savoir si une variable est définie
0
Le shell définit pour chaque commande un certain nombre de paramètres « automatiques ».
Tableau 10. Opérateurs de comparaison
| Paramètre(s) | Utilisation |
|---|---|
$0 | nom de la commande ou du script invoqué. |
$1, $2 .. $n ${1}, ${2} .. ${n} | encore équivalent à $argv[1], $argv[2], .. $argv[n] valeurs des paramètres positionnels passés à la commande ou au script. |
$* = $argv[*] = ${argv[*]} | ensemble des paramètres, sauf $0. |
$# = $#argv = ${#argv} | nombre de paramètres effectifs, $0 non compris. |
CODE : #!/bin/csh # ~/bin/testparm.sh echo 'je suis le script, $0 = ' $0 if ( ${#argv} > 0 ) then echo ' évoqué avec $# (= $#argv = ${#argv}) = ' ${#argv} ' arguments sur la ligne de commande' echo 'Voici les paramètres : $* (= $argv[*] = ${argv[*]}) = ' ${argv[*]} set i = 1 foreach param ( $argv[*] ) écho "paramètres ($i) : $param" @ i++ end else echo ' pas d arguments, nb arg $# (= $#argv = ${#argv}) = ' ${#argv} endif # fin du script EXEMPLE : $ ./testparam.sh toto titi tutu 147 je suis le script, $0 = ./testparam.sh évoqué avec $# (= $#argv = ${#argv}) = 4 arguments sur la ligne de commande Voici les paramètres : $* (= $argv[*]) = toto titi tutu 147 paramètre (1) : toto paramètre (2) : titi paramètre (3) : tutu paramètre (4) : 147 $ $ ./testparam.sh je suis le script, $0 = ./testparam.sh pas d arguments, nb arg $# (= $#argv = ${#argv}) = 0 $
Elle se fait en utilisant la variable spéciale $<
CODE : #!/bin/csh # ~/bin/testread.sh echo -n " Votre réponse (o, n) ? " set rep = $< if ( $rep == o ) then echo "réponse oui" else echo autre réponse : $rep endif EXEMPLE : $ ./testread.sh Votre réponse (o, n) ? yes autre réponse : yes $ ./testread.sh Votre réponse (o, n) ? o réponse oui
Règles :
Les expressions utilisent les mêmes opérateurs que le langage C (sémantique identique (sauf marque : (¢), c.f. « Tableau 11, « Opérateurs de comparaison » »)). On retrouve les instructions if, while, @ et exit,
Les chaines numériques commençant par un 0 sont interprétées comme des valeurs en base octale,
Le résultat de toute expression est une chaîne représentant un nombre décimal.
La valeur 0 s'interprète en contexte logique comme la valeur « faux », toutes les autres ont la valeur « vrai ».
Tableau 11. Opérateurs de comparaison
| Opérateur | Sémantique |
|---|---|
| O P E R A T E U R S D E F I C H I E R S | |
-d <filename> | (¢) est vraie si le fichier désigné par <filename> est un répertoire. |
-e <filename> | (¢) est vraie si le fichier désigné par <filename> existe. |
-f <filename> | (¢) est vraie si le fichier désigné par <filename> est un fichier régulier. |
-o <filename> | (¢) est vraie si le fichier désigné par <filename> est propriété de l'utilisateur. |
-r <filename> | (¢) est vraie si le fichier désigné par <filename> est un fichier accessible en lecture. |
-w <filename> | (¢) est vraie si le fichier désigné par <filename> est un fichier accessible en écriture. |
-x <filename> | (¢) est vraie si le fichier désigné par <filename> est un fichier exécutable. |
-z <filename> | (¢) est vraie si le fichier désigné par <filename> est de taille nulle. |
-b <filename> | [tcsh] (¢) est vraie si le fichier désigné par <filename> est un fichier spécial en mode bloc. |
-c <filename> | [tcsh] (¢) est vraie si le fichier désigné par <filename> est un fichier spécial en mode caractère. |
-l <filename> | [tcsh] (¢) est vraie si le fichier désigné par <filename> est un lien symbolique. |
-p <filename> | [tcsh] (¢) est vraie si le fichier désigné par <filename> est un tube nommés (FIFO). |
-S <filename> | [tcsh] (¢)est vraie si le fichier désigné par <filename> est un socket. |
| C O M P A R A I S O N D E C H A I N E S | |
<str1> == <str2> | est vraie si <str1> est égale à <str2>. |
<str1> != <str2> | est vraie si <str1> est différente de <str2>. |
<str1> =~ <str2> | (¢) est vraie si le motif <str2> (right hand side) correspond au motif <str1>. |
<str1> !~ <str2> | (¢) est vraie si le motif <str2> (right hand side) ne correspond pas au motif <str1>. |
| C O M P A R A I S O N D ' E N T I E R S | |
<int1> >= <int2> | est vraie si <int1> est supérieur ou égal à <int2>. |
<int1> > <int2> | est vraie si <int1> est strictement supérieur à <int2>. |
<int1> <= <int2> | est vraie si <int1> est inférieur ou égal à <int2>. |
<int1> < <int2> | est vraie si <int1> est strictement inférieur à <int2>. |
| C O M B I N A I S O N D ' E X P R E S S I O N S | |
| ( <expr> ) | est vraie si <expr> est vraie. |
! <expr> | est vraie si <expr> est fausse. |
<expr1> && <expr2> | est vraie si <expr1> et <expr2> sont simultanément vraies. |
<expr1> || <expr2> | est vraie si <expr1> ou <expr2> est/sont vraie(s). |
Tableau 12. Opérateurs (par ordre décroissant de priorité)
| Opérateurs | Sémantique |
|---|---|
| ( ) | regroupement |
| ~ | complément bit à bit |
| ! | négation logique. |
| * / % | multiplication, division, modulo |
| + - | addition, soustraction |
| << >> | décalage à gauche, décalage à droite |
| <= < >= > | opérateurs relationnels |
| == != =~ !~ | opérateurs de comparaisons de chaînes |
| & | « et » bit à bit |
| ^ | « ou exclusif » bit à bit |
| | | « ou » (inclusif) bit à bit |
| && | « et » logique |
| || | « ou » logique |
La commande interne @ permet de réaliser des opérations arithmétiques sur des valeurs ou variables entières, attention à respecter l'espace entre le symbole @ et la variable.
$ set v = 3 $ set u = 8 $ set p = 5 $ @ x = $v + $u * $p # attention à la priorité des opérateurs $ echo $x 43 $ @ x = ( $v + $u ) * $p 55 $ @ q = $u / $p # division entière $ @ r = $u % $p $ echo quotient = $q et reste = $r quotient = 1 et reste = 3 $ @ v++ # incrémentation d'une unité $ echo $v 4 $ @ v += 2 # incrémentation de deux unités $ echo $v 6 $ @ u /= 2 # @ u = u / 2 $ echo $u 4 $ @ u = ( $u << 3 ) # décalage à gauche de 3 bits, ce qui revient à une x 8 $ echo $u 32 $ @ v = (( $v + 4 ) >> 2 ) # 10 décaler de 2 bits à droite, soit 10 / 4 = 2 $ echo $v 2
Sous tcsh le mécanisme de completion des noms a été amélioré. Ce shell peut compléter les noms des fichiers, des commandes et des variables. De plus la completion des noms de fichiers est programmable !
La completion est déclenchable par la touche <TAB>, bien que par compatibilité ascendante avec csh, la touche <ESC> reste opérationnelle.
Contexte de variables : Il faut utiliser le préfixe $ (il change le contexte de la completion) :
$ set varia_1=10 $ echo $var<TAB> $ echo $varia_1 <ENTREE> 10
Cette commande permet l'édition des commandes en ligne dans un buffer au moyen des contrôles associés aux éditeurs classiques d'Unix, à savoir vi ou emacs. Utilisée seule, elle retourne la liste des associations clés/commandes.
Le positionnement par défaut est souvent le mode emacs, il est déterminé à la compilation. La variable version permet de connaître la version de la commande ainsi que les options de compilation. Dans l'exemple suivant, l'absence de la clé vi, permet d'affirmer que le mode par défaut est emacs.
$ echo $version tcsh 6.12.00 (Astron) 2002-07-23 (i386-intel-FreeBSD) options 8b,nls,dl,al,kan,s m,rh,color,dspm,filec
Cette commande permet aussi de commuter entre le mode vi et le mode emacs.
$ bindkey -e # mode emacs $ bindkey -v # mode vi
Dans le tableau suivant, nous présentons un sous-ensemble des commandes d'édition :
Tableau 13. Quelques couples clé/commande en mode emacs
| Clé | Commande |
|---|---|
| ^A | Positionne le curseur en début de ligne |
| ^B | Recule horizontalement le curseur d'un caractère |
| ^E | Postionne le curseur en fin de ligne |
| ^L | Efface l'ecran |
| ^K | Coupe tous les caractères à la droite du curseur |
| ^T | Transposition de caractères |
| ^M | Nouvelle ligne |
| ^U | Efface toute la ligne |
| ^C | Signal d'interruption |
| ^Z | Signal de suspension |
| Backspace | Efface le premier caractère situé à gauche du curseur |
| Flèche gauche | Déplacement d'un caractère à gauche du curseur |
| Flèche droite | Déplacement d'un caractère situé à droite du curseur |
| Flèche haut | Remonte dans l'historique des commandes (vers les commandes les plus anciennes) |
| Flèche bas | Descend dans l'historique des commandes |
Ce mécanisme est déclenché en postionnant la variable (interne) tcsh correct (valeurs possibles cmd ou all) :
$ set correct = cmd $ lzss test.csh # ooops typo ! CORRECT>less test.csh (y|n|e|a)? yes # frappe de la touche y ou <ESPACE> #!/bin/csh # lecture et affichage du fichier echo '\nJe suis le programme $0 : ' $0 ...
Soit les affectations suivantes :
$ set x=date $ set y=foobar
Tester les commandes suivantes et expliquer dans chaque cas le résultat obtenu.
$ echo $x ; echo $y ; echo $z $ echo "$x" ; echo "$y" ; echo "$z" $ echo '$x' ; echo '$y' ; echo '$z' $ echo `$x` ; echo `$y` ; echo `$z` $ $x ; $y ; $z $ "$x" ; "$y" ; "$z" $ '$x' ; '$y' ; '$z' $ `$x` ; `$y` ; `$z` $ $y=`$x` $ echo $foobar
Tester les commandes suivantes et expliquer dans chaque cas le résultat obtenu.
$ echo pwd $ `echo pwd` $ 'echo pwd' $ "echo pwd" $ echo echo pwd $ echo `echo pwd` $ echo 'echo pwd' $ echo "echo pwd" $ echo '`echo pwd`' $ echo '`echo pwd`'
Dans un terminal, sous le shell courant définir deux variables (var1 et var2) et modifier quelques variables d'environnement. Afficher l'environnement ainsi modifié.
Dans ce même terminal, empiler un nouveau shell (/bin/tcsh). Quelle sont les valeurs de var1 et var2, des variables d'environnement ? Définir une variable var3.
Quitter ce shell et revenir à l'environnement initial (exit). Examiner son environnement, que vaut var3 ? Conclure.
Exporter maintenant la variable var1, empiler un nouveau shell. Examiner son environnment. Modifier ensuite var1. Définir la variable var2. Quitter ce shell, pour revenir à celui de départ. Quelles sont les valeurs de var1 et var2 ?
Et si avant de quitter ce shell empilé, vous aviez exporté la variable var2, qu'auriez-vous obtenu ?
Exécuter la commande suivante dans un premier terminal, et dans un second ouvert pour l'occasion, lister les processus en cours d'exécution (se limiter aux seuls processus du terminal « générateur »), observer leur filiation, le nombre de processus :
$ ( ls -la /usr/bin/ ; sleep 5 ; echo "5 - OK" ; last ) & \ ( cat /etc/passwd ; sleep 7 ; echo "7 - OK" ; cat /etc/group ) & ps aux
Observer l'entrelacement des résulats de ces commandes.
La séquence backslash (i.e. \), suivit de la touche <Entrée> indique au shell une continuation de la commande sur la ligne suivante. Que fait la commande sleep ?
Lancer la commande suivante : find / -type d -print, laquelle recherche tous les objets de type répertoire dans toute l'arborescence. La recherche se fait de manière récursive et comme l'arborescence est grande, l'exécution est un peu longue. On est bloqué tant que le processus exécutant le find n'est pas terminé. Il vous est demandé de :
suspendre (ou stopper) le processus.
de le relancer en arrière-plan
de le ramener au premier plan
de le terminer.
Est-il possible de « tuer » des processus ne vous appartenant pas ? Tester-le.
Si vous n'êtes pas assez rapide ou bien si la commande s'exécute trop rapidement, ouvrir un nouveau terminal et refaire le travail demandé.
Reprendre l'exemple de la commande find, de la section « Section 2.10, « Redirection de commandes » », mais limiter la recherche au répertoire /etc.
Rediriger uniquement la sortie d'erreur dans le fichier (ferr) ;
Rediriger uniquement la sortie standard dans un fichier (fout) ;
Multiplexer les sorties standard et d'erreur dans le même fichier (fouterr) ;
Rediriger (démultiplexer) la sortie standard et la sortie d'erreur dans les fichiers respectifs (fout et ferr).
[0] csh. man csh. Janvier 1994.
[1] Making friends with C-Shell and TC-shell, Part I. http://ezine.daemonnews.org/200112/. Décembre 2001.
[2] Making friends with C-Shell and TC-shell, Part II. http://ezine.daemonnews.org/200201/. Janvier 2002.
[3] Making friends with C-Shell and TC-shell, Part III. http://ezine.daemonnews.org/200202/. Février 2002.
[4] The C Shell tutorial. csh tutorial. 2001.
[5] Unix. Utilisation, Administration, Réseau Internet. Chap 9, pp 163-176. HERMES. 1992, 1995, 1996, 1998. isdn : 2-86601-707-2.