Les langages de script Bash Tcsh Tclsh
Bonjour,
Cette page, concernant les shell-scripts, doit être lue, relue, ... et relue ;)
N'hésitez pas à y revenir régulièrement : vous y découvrirez et comprendrez toujours quelque chose de plus, au fur et à mesure de la pratique.
Il y a tellement de choses à assimiler qu'on ne peut pas tout comprendre à la première lecture.
Nous y parlerons des shells bash et tcsh ... et introduirons tclsh.
0/ Remarque prélimaire concernant la séparation des mots d'une commande
La syntaxe des langages de programmation nous fait apparaître deux types de langages.
- Les langages ressemblant à des script sh, bash, tclsh, etc qui utilisent l'espace comme séparateur des mots d'une commande
- Les autres : C, Java, Python, Php, Javascript, ... qui utilisent les parenthèses, et la virgule comme séparateurs.
En général pour les langages de la deuxième catégorie les espaces (hors chaînes de caractères) ne servent à rien et peuvent presque toujours être supprimés. En gros ils ne servent qu'à aérer le texte et le rendre lisible à l'humain.
Mais pour la première catégorie ils sont hyper-importants et sauf exception (dans les chaînes de caractères par ex.) une suite de plusieurs espaces peut être remplacée par un seul espace.
Bien sûr tout n'est pas si stricte ... il y a aussi des () {} dans les langages de script, ... rarement des virgules.
CE QU'IL FAUT COMPRENDRE POUR 0/ : les mots d'une commande sont séparés par un espace, les autres langages utilisent des virgules
Quand vous êtes dans un terminal en bash ou tcsh à taper des commandes ... que se passe-t-il ?
1/ commande et arguments
cp arthur.truc /home/ripp/la/toto.truc
.. ----------- +++++++++++++++++++++++
cp est la commande
arthur.machin le premier argument de la commande
/home/ripp/la/toto.truc le deuxième argument de la commande
et ... vous l'aurez compris on copie le fichier arthur.truc en /home/ripp/la/toto.truc
(il change de nom ... arthur.truc devient toto.truc)
(sauf si toto.truc est un répertoire qui existe déjà,
dans ce cas on crée /home/ripp/la/toto.truc/arthur.machin
... ne rigolez pas ça arrive souvent et on n'y comprend plus rien ...
je donnerai des exemples déroutants ci-dessous)
CE QU'IL FAUT COMPRENDRE POUR 1/ : commande argument1 argument2 argument3
2/ Mais qu'est ce qu'une commande ?
C'est TOUJOURS et UNIQUEMENT : (... et dans cet ordre, premier arrivé premier servi)
a) un 'alias' du shell dans lequel on est
b) un 'commande interne' du shell
c) un 'fichier qui existe' et que l'on exécute (il faut avoir les droits d'exécution (voir plus bas))
ce fichier doit obligatoirement apparaître dans un des répertoires cités dans le 'path'
... il se peut qu'au lieu d'être un vrai fichier ce peut aussi être un 'lien' (qui apparaît dans le path)
... ce lien pointe vers un fichier existant qui peut se trouver n'importe où
... même en dehors des répertoires cités dans le path
CE QU'ILFAUT COMPRENDRE POUR 2/ : c'est TOUJOURS et UNIQUEMENT a, b ou c
3/ Qu'est le path ?
C'est une variable du shell qui contient une liste (l'ordre est important) de répertoires dans lesquels on trouve des fichiers ou des liens
Quand on tape une commande qui n'est pas un alias ou une commande du shell :
Le shell prend le premier répertoire cité dans le path et y cherche le fichier du nom de la commande
Si'il n'y est pas il passe au suivant
... etc.
(S'il ne le trouve nulle part il affiche "command not found")
CE QU'IL FAUT COMPRENDRE POUR 3/ : c'est la variable path (ou PATH) du shell qui contient une liste ordonnée de répertoires
4/ Le path est prédéfini mais peut être modifié
le path est typiquement par exemple : /usr/local/bin:/usr/local/bin/X11:/bin:/sbin:/usr/sbin:/usr/bin:/usr/bin/X11:/home/raymond/bin:.
Les répertoires sont ici séparés par ":"
Si le fichier du nom de la commande apparaît par exemple à la fois dans /usr/local/bin/X11 et /home/raymond/bin
... c'est celui de /usr/local/bin/X11 qui est pris.
Remarquez le "." à la fin : ça veut dire qu'on cherche aussi dans le répertoire courant ;)
... Donc suivant le cd (change directory) qui a été fait précédemment on peut exécuter autre chose
... ou ne plus le trouver ...
... Ca peut être dangereux aussi, et il est préférable de l'avoir en dernier ... POURQUOI ?
... Imaginez que quelqu'un ait créer un fichier s'appelant "cp" caché dans /quelqun/data ... si vous êtes dans ce répertoire et que vous croyez faire un copy
... cd /quelqun/data ; cp notes.xls /ici/
... vous allez exécuter /autre/data/cp qui s'exécute en votre nom avec vos droits ... !
Comment modifier le path ?
set path=/nouveaurep/:$path
... il y a plein d'autres manières, nous y reviendrons plus tard
CE QU'IL FAUT COMPRENDRE POUR 4/ : il est prédéfini.
5/ Qu'est un fichier exécutable ?
C'est TOUJOURS et UNIQUEMENT (si ce n'est pas un alias ou une commande du shell)
- un fichier script contenant des commandes dans un langage script quelconque (bash, sh, tcsh, tclsh, python, php ...)
- un fichier 'exécutable' qui a été compilé à partir de programmes 'source' en C, fortran, java, ...
Attention ceci inclue les commande du type
java bidule.jar
python /home/ripp/monpython.py
ls *.txt
bash monscript.sh
rm *.xls
libreoffice rapport.odt
et bien sûr
JeuDernierCri.exe (acheté
calculeMoyenne (obtenu par exemple par cc calculMoyenne.c -o calculeMoyenne)
Je dirai plus loin comment on peut faire en sorte que
python /home/ripp/monpython.py
puisse aussi s'exécuter en tapant
monpython
CE QU'IL FAUT COMPRENDRE POUR 5/ : c'est un exécutable compilé ou un script
6/ De l'importance de bien séparer les mots
A priori toute chaîne de caractères entre doubles quotes ("...") ou simples quotes ('...') peut être considérée comme un seul mot.
Ainsi
EcritLettre "Bonjour Madame" CorpsDutexte "Meilleures salutations"
peut être considéré comme une commande avec 3 arguments l'entête, le corps et la salutation.
Mais attention, ne pas oublier de séparer chaque argument par au moins un blanc.
Il en est de même pour les instruction un peu plus compliquées, ... surtout en bash qui est très sensible moins en tcsh et tclsh
Ainsi :
en bash
if [ "$texte" = "Bonjour" ] ; then echo "Bonjour" ; else echo "Bonjoir"
Remarquez les blancs entourant les [ , ] , et = . Ils sont indispensables !!!
Reparquez aussi les quotes " " autour de $texte ... il vaut mieux les mettre car si texte est vide il est remplacé par rien et du coup l'argument disparaît :'(
En fait, en bash, vous allez rire : '[' est une commande qui fait la même choses que 'test' (avec le ']' en fin obligatoire)
which [ donne /usr/bin/[
en tcsh
if ( "$texte" = "Bonjour" )
CE QU'IL FAUT COMPRENDRE POUR 6/ : bien comprendre comment les commandes détectent chaque argument
7/ Convertir un texte en liste et réciproquement
C'est plus ou moins facile en fonction du langage utilisé
En supposant T = "Un Deux Trois Quatre Cinq Six " (il y a 2 blancs entre Trois et Quatre, 3 entre Quatre et Cinq et 1 blanc à la fin
!!!!!!!!!! en bash ou tcsh les blancs multiples sont systématiquement remplacés par un seul
DONC ... on oublie. ON ne mùanipule pas des chaînes de caractères sompliquées en bash ou tcsh ... c'est pas fait pour.
bash : L=($T) ; echo ${L[*]} Un Deux Trois Quatre Cinq Six
tcsh : set L=($T) ; echo $L Un Deux Trois Quatre Cinq Six
tclsh : set L [split $T] ; puts $L Un Deux Trois {} Quatre {} {} Cinq Six {}
python : L = T.split(" ") ; print L ['Un', 'Deux', 'Trois', '', 'Quatre', '', '', 'Cinq', 'Six', '']
javascript : L = T.split(" ") ; console.log(L) ['Un', 'Deux', 'Trois', '', 'Quatre', '', '', 'Cinq', 'Six', '']
pour le join (par la virgule mais tout autre caractère est pareil)
tclsh : puts [join $L ,] Un,Deux,Trois,,Quatre,,,Cinq,Six,
python : print ",".join(L) Un,Deux,Trois,,Quatre,,,Cinq,Six,
javascript : console.log(L.join(",") Un,Deux,Trois,,Quatre,,,Cinq,Six,
CE QU'IL FAUT COMPRENDRE POUR 7/ : très délicat en bash et tcsh. Sinon split et join marchent bien.