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.