Chapitre 6. Groupement de commandes

Le shell fournit deux mécanismes pour grouper l’exécution d’un ensemble de commandes sans pour cela affecter un nom à ce groupement :

  1. {suite_cmds;}

    Insérée entre une paire d’accolades, la suite de commandes est exécutée dans le shell courant. Cela a pour effet de préserver les modifications apportées par la suite de commandes sur l’environnement du processus courant.

    $ pwd
    /home/sanchis            => répertoire initial
    $
    $ { cd /bin ; pwd ; }    => changement du répertoire courant
    /bin
    $
    $ pwd
    /bin                     => répertoire final (le changement a été préservé !)
    $

    S’exécutant dans le shell courant, les modifications apportées aux variables sont également conservées :

    $ a=bonjour
    $
    $ { a=coucou ; echo $a ;}
    coucou
    $
    $ echo $a
    coucou
    $

    Les accolades { et } sont deux mots-clé de bash ; chacune d’elles doit donc être le premier mot d’une commande. Pour cela, chaque accolade doit être le premier mot de la ligne de commande ou bien être précédée d’un caractère ;. De plus, suite_cmds ne doit pas « coller » l’accolade ouvrante {.

    Par contre, la présence ou absence d’un caractère espace entre le caractère ; et le mot-clé } n’a aucune importance.

    $ { cd /bin }      => l’accolade } n’est pas le premier mot d’une commande
    >               => le shell ne détecte pas la fin du groupement
    > ^C            => control-C
    $
    $ {cd /bin ;}      => il manque un espace ou une tabulation entre { et cd
    bash: Erreur de syntaxe près du symbole inattendu « } »
    $

    Lancée en arrière-plan, la suite de commandes n’est plus exécutée par le shell courant mais par un sous-shell.

    $ pwd
    /home/sanchis      => répertoire initial
    $
    $ { echo processus : ; cd / ; ps ;} &
    processus :
    [1] 27963
    $ PID    TTY     TIME CMD
    27942 pts/14 00:00:00 bash
    27947 pts/14 00:00:00 bash
    27963 pts/14 00:00:00 ps
    
    [1] + Done { echo processus :; cd /; ps; }
    $
    $ pwd
    /home/sanchis      => répertoire final
    $

    Bien qu’une commande cd / ait été exécutée, le répertoire courant n’a pas été modifié (/home/sanchis).

    Une utilisation fréquente du regroupement de commandes est la redirection globale de leur entrée ou sortie standard.

    $ cat fich
    premiere ligne
    deuxieme ligne
    troisieme ligne
    quatrieme ligne
    $
    $ { read ligne1 ; read ligne2
    > } < fich     => le caractère > est affiché par le shell, indiquant que l’accolade } est manquante
    $                    
    $ echo $ligne1
    premiere ligne
    $ echo $ligne2
    deuxieme ligne
    $

    L’entrée standard des deux commandes read ligne1 et read ligne2 est globalement redirigée : elles liront séquentiellement le contenu du fichier fich.

    Si les commandes de lecture n’avaient pas été groupées, seule la première ligne de fich aurait été lue.

    $ read ligne1 < fich ; read ligne2 < fich
    $
    $ echo $ligne1
    premiere ligne
    $
    $ echo $ligne2
    premiere ligne
    $

    Comme pour toutes commandes composées, lorsque plusieurs redirections de même type sont appliquées à la même suite de commandes, seule la redirection la plus proche est effective.

    $ { read lig1 ; read -p "Entrez votre ligne : " lig2 </dev/tty
    > read lig3
    > } < fich
    Entrez votre ligne : bonjour tout le monde
    $
    $ echo $lig1
    premiere ligne
    $ echo $lig2
    bonjour tout le monde
    $ echo $lig3
    deuxieme ligne
    $

    Les commandes read lig1 et read lig3 lisent le contenu du fichier fich mais la commande read -p "Entrez votre ligne : " lig2 lit "le clavier" (/dev/tty).

  2. (suite_cmds;)

    Insérée entre une paire de parenthèses, la suite de commandes est exécutée dans un sous-shell. L’environnement du processus n’est pas modifié après exécution de la suite de commandes.

    Les parenthèses sont des opérateurs (et non des mots-clé) : suite_cmds peut par conséquent coller une ou deux parenthèses sans provoquer une erreur de syntaxe.

    $ pwd
    /home/sanchis    => répertoire initial
    $
    $ (cd /bin ; pwd)
    /bin
    $
    $ pwd
    /home/sanchis    => le répertoire initial n’a pas été modifié
    $
    $ b=bonjour
    $
    $ ( b=coucou ; echo $b )
    coucou
    $
    $ echo $b
    bonjour          => la valeur de la variable b n’a pas été modifiée
    $

    Ce type de groupement de commandes peut aussi être utilisé pour effectuer une redirection globale.

    $ ( pwd ; date ; echo FIN ) > fin
    $
    $ cat fin
    /home/sanchis
    lundi 31 mars 2014, 10:55:31 (UTC+0200)
    FIN
    $