37.3. Bash, version 4

La sortie de Bash version 4 a été annoncée le 20 février 2009, par Chet Ramey. Cette livraison comprenait un certain nombre de fonctionnalités notables ainsi que des corrections majeures.

Parmi les nouveautés :

37.3.1. Bash, version 4.1

La version 4.1 of Bash, publiée en mai 2010, était pour l'essentiel une mise à jour de correctifs.

  • La commande printf accepte maintenant l'option -v pour assigner les indexes des tableaux.

  • Entre les crochets doubles, les opérateurs de comparaison de chaînes de caractères > et < se conforment à présent à la locale. Étant donné que le réglage de la locale peut affecter l'ordre de tri des expressions littérales, il y a un risque d'effets de bord sur les tests de comparaison des expressions entre [[ ... ]].

  • La fonction intégrée read accepte maintenant l'option -N (read -N nb_car). Cette option provoque la sortie de read après nb_car caractères.

    Exemple 37.8. Lecture de N caractères

    #!/bin/bash
    # Requires Bash version -ge 4.1 ...
    
    num_chars=61
    
    read -N $num_chars var < $0   # Read first 61 characters of script!
    echo "$var"
    exit
    
    ####### Output of Script #######
    
    #!/bin/bash
    # Requires Bash version -ge 4.1 ...
    
    num_chars=61
    

  • A VERIF

    Here documents, intégrés dans une substitution de commande de la forme $( ... ), peuvent de terminer avec une simple ).

    Exemple 37.9. Utilisation d'un here document pour assigner une valeur à une variable

    #!/bin/bash
    # here-commsub.sh
    # Requires Bash version -ge 4.1 ...
    
    multi_line_var=$( cat <<ENDxxx
    ------------------------------
    This is line 1 of the variable
    This is line 2 of the variable
    This is line 3 of the variable
    ------------------------------
    ENDxxx)
    
    #  Rather than what Bash 4.0 requires:
    #+ that the terminating limit string and
    #+ the terminating close-parenthesis be on separate lines.
    
    # ENDxxx
    # )
    
    
    echo "$multi_line_var"
    
    #  Bash still emits a warning, though.
    #  warning: here-document at line 10 delimited
    #+ by end-of-file (wanted `ENDxxx')
    

37.3.2. Bash, version 4.2

La version 4.2 of Bash, publiée en février 2011, contient un certain nombre de nouvelles fonctionnalités et d'améliorations, en plus des corrections de bugs.

  • Bash implémente à présent les échappements Unicode \u et \U.

    echo -e '\u2630'   
                                 # Caractère triple tiret horizontal empilé
    # Équivaut à la formulation détournée suivante :
    echo -e "\xE2\x98\xB0"
                       # Reconnue par les versions de Bash antérieures.
    
    echo -e '\u220F'   # Pi (lettre grecque et symbole mathématique)
    echo -e '\u0416'   # "Zhe" majuscule (caractère cyrillique)
    echo -e '\u2708'   # Symbole avion (police Dingbat)
    
    echo -e "Le circuit de cet amplificateur nécessite une résistance de tirage de 100 \u2126."  
    
    var_unicode='\u2640'
    echo -e $var_unicode      # Symbole féminin
    printf "$var_unicode \n"  # Symbole féminin avec retour à la ligne
    
    #  Et pour un cas un peu plus recherché...
    
    #  On peut stocker les symboles Unicode dans un tableau associatif
    #+ pour ensuite les retrouver par leur nom.
    #  Lancez cet exemple dans un terminal Gnome, ou un terminal muni
    #+ d'une police assez grosse et grasse pour la lisibilité.
    
    declare -A symbole  # Tableau associatif.
    
    symbole[script_E]='\u2130'
    symbole[script_F]='\u2131'
    symbole[script_J]='\u2110'
    symbole[script_M]='\u2133'
    symbole[Rx]='\u211E'
    symbole[TEL]='\u2121'
    symbole[FAX]='\u213B'
    symbole[care_of]='\u2105'
    symbole[account]='\u2100'
    symbole[trademark]='\u2122'
    
    
    echo -ne "${symbole[script_E]}   "
    echo -ne "${symbole[script_F]}   "
    echo -ne "${symbole[script_J]}   "
    echo -ne "${symbole[script_M]}   "
    echo -ne "${symbole[Rx]}   "
    echo -ne "${symbole[TEL]}   "
    echo -ne "${symbole[FAX]}   "
    echo -ne "${symbole[care_of]}   "
    echo -ne "${symbole[account]}   "
    echo -ne "${symbole[trademark]}   "
    echo
    
    [Note]

    Note

    L'exemple ci-dessus utilise la syntaxe de développement de chaînes $' ... '.

  • Lorsque l'option du shell lastpipe est mise, la dernière commande dans un pipe n'est pas exécutée dans un sous-shell.

    Exemple 37.10. Envoyer (par pipe) un flux d'entrée vers read

    #!/bin/bash
    # lastpipe-option.sh
    
    line=''                   # Null value.
    echo "\$line = "$line""   # $line =
    
    echo
    
    shopt -s lastpipe         # Error on Bash version -lt 4.2.
    echo "Exit status of attempting to set \"lastpipe\" option is $?"
    #     1 if Bash version -lt 4.2, 0 otherwise.
    
    echo
    
    head -1 $0 | read line    # Pipe the first line of the script to read.
    #            ^^^^^^^^^      Not in a subshell!!!
    
    echo "\$line = "$line""
    # Older Bash releases       $line =
    # Bash version 4.2          $line = #!/bin/bash
    

    Cette option apporte éventuellement des « correctifs » pour ces scripts d'exemple : Exemple 34.3, « Envoyer la sortie de echo dans un tube pour un read » et Exemple 15.8, « Problèmes lors de la lecture d'un tube ».

  • Les indices de tableau négatifs permettent le décompte à l'envers, depuis la fin d'un tableau.

    Exemple 37.11. Indices de tableau négatifs

    #!/bin/bash
    # neg-array.sh
    # Requires Bash, version -ge 4.2.
    
    array=( zero one two three four five )   # Six-element array.
    
    # Negative array indices now permitted.
    echo ${array[-1]}   # five
    echo ${array[-2]}   # four
    # ...
    echo ${array[-6]}   # zero
    # Negative array indices count backward from the last element+1.
    
    # But, you cannot index past the beginning of the array.
    echo ${array[-7]}   # array: bad array subscript
    
    
    # So, what is this new feature good for?
    
    echo "The last element in the array is "${array[-1]}""
    # Which is quite a bit more straightforward than:
    echo "The last element in the array is "${array[${#array[*]}-1]}""
    echo
    
    # And ...
    
    index=0
    let "neg_element_count = 0 - ${#array[*]}"
    # Number of elements, converted to a negative number.
    
    while [ $index -gt $neg_element_count ]; do
      ((index--)); echo -n "${array[index]} "
    done  # Lists the elements in the array, backwards.
          # We have just simulated the "tac" command on this array.
    
    echo
    

  • L'extraction de sous-chaîne utilise un paramètre de longueur négative pour spécifier un intervalle depuis la fin de la chaîne cible.

    Exemple 37.12. Paramètre négatif dans une extraction de chaîne

    #!/bin/bash
    # Bash, version -ge 4.2
    # Negative length-index in substring extraction.
    # Important: This changes the interpretation of this construct!
    
    stringZ=abcABC123ABCabc
    
    echo ${stringZ}                              # abcABC123ABCabc
    echo ${stringZ:2:3}                          #   cAB
    #  Count 2 chars forward from string beginning, and extract 3 chars.
    #  ${string:position:length}
    
    #  So far, nothing new, but now ...
    
    echo ${stringZ:3:-6}                         #    ABC123
    #                ^
    #  Index 3 chars forward from beginning and 6 chars backward from end,
    #+ and extract everything in between.
    #  ${string:offset-from-front:offset-from-end}
    #  When the "length" parameter is negative, 
    #+ it serves as an "offset-from-end" parameter.
    



[123] Plus particulièrement, Bash à partir de la version 4 comprend un support limité des tableaux associatifs. C'est une implémentation de base, à laquelle il manque la plupart des fonctionnalités des tableaux du même genre dans les autres langages de programmation.

[124] Copyright 1995-2009 by Chester Ramey.

[125] Ceci ne fonctionne qu'avec les tubes et quelques autres fichiers spéciaux.

[126] Mais seulement en association avec readline, c'est-à-dire depuis la ligne de commande.

[127] Et pendant que vous y êtes, pensez à remédier au problème bien connu du piped read.