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 de bugs majeures.
Parmi les nouveautés :
Exemple 34.5. Petite base de données d'adresses
#!/bin/bash4 # fetch_address.sh declare -A address # -A option declares associative array. address[Charles]="414 W. 10th Ave., Baltimore, MD 21236" address[John]="202 E. 3rd St., New York, NY 10009" address[Wilma]="1854 Vermont Ave, Los Angeles, CA 90023" echo "Charles's address is ${address[Charles]}." # Charles's address is 414 W. 10th Ave., Baltimore, MD 21236. echo "Wilma's address is ${address[Wilma]}." # Wilma's address is 1854 Vermont Ave, Los Angeles, CA 90023. echo "John's address is ${address[John]}." # John's address is 202 E. 3rd St., New York, NY 10009.
Exemple 34.6. Base de données d'adresses un peu plus élaborée
#!/bin/bash4 # fetch_address-2.sh # A more elaborate version of fetch_address.sh. SUCCESS=0 E_DB=99 # Error code for missing entry. declare -A address # -A option declares associative array. store_address () { address[$1]="$2" return $? } fetch_address () { if [[ -z "${address[$1]}" ]] then echo "$1's address is not in database." return $E_DB fi echo "$1's address is ${address[$1]}." return $? } store_address "Charles Jones" "414 W. 10th Ave., Baltimore, MD 21236" store_address "John Smith" "202 E. 3rd St., New York, NY 10009" store_address "Wilma Wilson" "1854 Vermont Ave, Los Angeles, CA 90023" # Exercise: # Rewrite the above store_address calls to read data from a file, #+ then assign field 1 to name, field 2 to address in the array. # Each line in the file would have a format corresponding to the above. # Use a while-read loop to read from file, sed or awk to parse the fields. fetch_address "Charles Jones" # Charles Jones's address is 414 W. 10th Ave., Baltimore, MD 21236. fetch_address "Wilma Wilson" # Wilma Wilson's address is 1854 Vermont Ave, Los Angeles, CA 90023. fetch_address "John Smith" # John Smith's address is 202 E. 3rd St., New York, NY 10009. fetch_address "Bozo Bozeman" # Bozo Bozeman's address is not in database. exit $? # In this case, exit code = 99, since that is function return.
Amélioration de la syntaxe de case : caractères de fin ;;& et ;&.
Exemple 34.7. Tests de caractères
#!/bin/bash4 test_char () { case "$1" in [[:print:]] ) echo "$1 is a printable character.";;& # | # The ;;& terminator continues to the next pattern test. | [[:alnum:]] ) echo "$1 is an alpha/numeric character.";;& # v [[:alpha:]] ) echo "$1 is an alphabetic character.";;& # v [[:lower:]] ) echo "$1 is a lowercase alphabetic character.";;& [[:digit:]] ) echo "$1 is an numeric character.";& # | # The ;& terminator executes the next statement ... # | %%%@@@@@ ) echo "********************************";; # v # ^^^^^^^^ ... even with a dummy pattern. esac } echo test_char 3 # 3 is a printable character. # 3 is an alpha/numeric character. # 3 is an numeric character. # ******************************** echo test_char m # m is a printable character. # m is an alpha/numeric character. # m is an alphabetic character. # m is a lowercase alphabetic character. echo test_char / # / is a printable character. echo # The ;;& terminator can save complex if/then conditions. # The ;& is somewhat less useful.
La nouvelle commande intégrée coproc permet à deux processus parallèles de communiquer et d'interagir. Voyez ce qu'écrit Chet Ramey dans la FAQ de Bash. [116] , ver. 4.01 :
Le nouveau mot réservé 'coproc' spécifie un
co-processus : une commande asynchrone tourne avec
deux tubes connectés au shell qui les a créés. Les
co-processus peuvent être nommés. Les descripteurs de
fichiers d'entrée et de sortie, les PID des co-processus
sont disponibles pour le shell appelant dans des
variables dont les noms renvoient au co-processus
concerné.
Les co-processus utilisent des descripteurs de fichiers. Les descripteurs de fichiers permettent aux processus et aux tubes de se parler.
#!/bin/bash4 # Un co-processus communique avec une boucle while-read coproc cat $0 while read -u ${COPROC[0]} line # ${COPROC[0]} est le do #+ descripteur de fichier du co-processus. echo "$line" | sed -e 's/line/TEXTE-NON-ORIGINAL/' done kill $COPROC_PID # Plus besoin du co-processus #+ donc on tue son PID.
Mais attention !
#!/bin/bash4 echo; echo a=aaa b=bbb c=ccc coproc echo "un deux trois" while read -u ${COPROC[0]} a b c; # Remarquez que cette boucle do #+ tourne dans un sous-shell. echo "Dans le boucle while-read : "; echo "a = $a"; echo "b = $b"; echo "c = $c" echo "descripteur de fichier du co-processus : ${COPROC[0]}" done # a = un # b = deux # c = trois # Jusque là, pas de problème, mais... echo "-----------------" echo "Hors de la boucle while-read : echo "a = $a" # a = echo "b = $b" # b = echo "c = $c" # c = echo "descripteur de fichier du co-processus : ${COPROC[0]}" echo # Le co-processus tourne toujours, mais... #+ il ne permet toujours pas au processus parent #+ d'"hériter" les variables du processus enfant, la boucle while-read # Comparez avec le script "badread.sh".
Le co-processus est asynchrone, ce qui peut poser problème. Il peut en effet se terminer avant qu'un autre processus ait fini de communiquer avec lui.
#!/bin/bash4 coproc nomcopr { for i in {0..10}; do echo "index = $i"; done; } # ^^^^^^^ Ce co-processus est *nommé*. read -u ${nomcopr[0]} echo $REPONSE # index = 0 echo ${COPROC[0]} #+ Aucun résultat... Le co-processus s'est terminé # après la première itération de la boucle.
La nouvelle commande intégrée mapfile permet de charger un tableau portant le contenu d'un fichier texte sans utiliser de boucle ni de substitution de commande.
#!/bin/bash4 mapfile Tabl1 < $0 # Même résultat que Tabl1=( $(cat $0) ) echo "${Tabl1[@]}" # Recopie tout ce script vers la sortie standard. echo "--"; echo # Mais pas le même que read -a !!! read -a Tabl2 < $0 echo "${Tabl2[@]}" # Lit seulement la première ligne du script #+ dans le tableau exit
La commande intégrée read a fait l'objet d'un léger lifting. L'option -t timeout accepte maintenant les valeurs (décimales) fractionnelles [117] et l'option -i permet le pré-chargement du tampon d'édition. [118] Malheureusement, l'implémentation des améliorations ci-dessus est encore en cours, elles ne sont donc pas (encore) utilisables dans des scripts.
La substitution de paramètre reçoit un nouvel opérateur de modification de la casse.
#!/bin/bash4 var=variableTresMelangee echo ${var} # variableTresMelangee echo ${var^} # VariableTresMelangee # * Premier caractère --> en majuscule echo ${var^^} # VARIABLETRESMELANGEE # ** Tous les caractères --> en majuscules echo ${var,} # variableTresMelangee # * Premier caractère --> en minuscule echo ${var,,} # variabletresmelangee # ** Tous les caractères --> en minuscules.
La commande intégrée declare accepte maintenant les options -l lowercase (en minuscules) et -c capitalize (capitaliser).
#!/bin/bash4 declare -l var1 # Changera en minuscules var1=VariableDeCasseMIXTE echo "$var1" # variabledecassemixte # Même effet que echo $var1 | tr A-Z a-z declare -c var2 # Changera juste le premier caractère en majuscule var2=au_depart_en_minuscules echo "$var2" # Au_depart_en_minuscules # PAS la même chose que echo $var2 | tr a-z A-Z
De nouvelles options pour le développement des accolades.
Incrémentation/décrémentation, spécifiée dans le dernier terme à l'intérieur des accolades.
#!/bin/bash4 echo {40..60..2} # 40 42 44 46 48 50 52 54 56 58 60 # Tous les nombres pairs de 40 à 60 echo {60..40..2} # 60 58 56 54 52 50 48 46 44 42 40 # Tous les nombres pairs entre 40 et 60, dans l'ordre inverse # Donc en fait c'est une décrémentation. echo {60..40..-2} # Même résultat. Le signe moins n'est pas nécessaire. # Est-ce que ça marche aussi avec les lettres et des symboles ? echo {X..d} # X Y Z [ ] ^ _ ` a b c d echo {X..d..2} # X Z ^ ` b d # On dirait bien que ça marche pour les lettres majuscules/minuscules, #+ mais l'incrémentation est un peu incohérente pour les #+ symboles.
Le remplissage avec des zéros, s'il est spécifié dans le premier terme à l'intérieur des accolades, ajoute le même nombre de zéros comme préfixe des nombres de la chaîne résultat.
bash4$ echo {010..15} 010 011 012 013 014 015 bash4$ echo {000..10} 000 001 002 003 004 005 006 007 008 009 010
L'extraction de sous-chaîne sur les paramètres de postion commence maintenant par $0, en tant qu'index zéro. (Ceci corrige une incohérence dans le traitement des paramètres de position.)
#!/bin/bash4 # montre-params.bash4 # Invoquer ces scripts avec au moins un paramètre de position. E_MAUVAISPARAMS=99 if [ -z "$1" ] then echo "Usage $0 param1 ..." exit $E_MAUVAISPARAMS fi echo ${@:0} # bash3 montre-params.bash4 un deux trois # un deux trois # bash4 montre-params.bash4 un deux trois # show-params.bash4 un deux trois # $0 $1 $2 $3
Le nouvel opérateur de remplacement ** attrape tous les noms de fichiers et les noms de répertoires, récursivement.
#!/bin/bash4 # listefichiers.bash4 shopt -s globstar # Il faut activer globstar pour que ** fonctionne # L'option du shell 'globstar' est une nouveauté #+ de Bash 4 echo "Avec *"; echo for nomfichier in * do echo "$nomfichier" done # Liste seulement les fichiers du répertoire courant ($PWD). echo; echo "--------------"; echo echo "Avec **" for nomfichier in ** do echo "$nomfichier" done # Liste intégralement, récursivement, #+ l'arborescence de fichiers exit Using * tousmesfichiers listefichiers.bash4 -------------- Avec ** tousmesfichiers tousmesfichiers/index.des.fichiers.txt tousmesfichiers/ma_musique tousmesfichiers/ma_musique/je-chante-des-chansons-des-annees-60.ogg tousmesfichiers/ma_musique/je-chante-de-l-opera.ogg tousmesfichiers/ma_musique/lecon-de-piano.1.ogg tousmesfichiers/mes_images tousmesfichiers/mes_images/a-la-plage-avec-Jade.png tousmesfichiers/mes_images/piqueniqye-avec-Melissa.png listefichiers.bash4
Nouvelle variable interne $BASHPID.
On a une nouvelle commande intégrée, une fonction de traitement d'erreur appelée command_not_found_handle.
#!/bin/bash4 command_not_found_handle () { # Accepte les paramètres implicites. echo "La commande suivante n'est pas valable : \""$1\""" echo "Avec l'(es) argument(s) suivant(s) : \""$2\"" \""$3\""" # $4, $5 ... } # $1, $2, etc... ne sont pas passés explicitement à la fonction. mauvaise_commande arg1 arg2 # La commande suivante n'est pas valable : "mauvaise_commande" # avec l'(es) argument(s) suivant(s) : "arg1" "arg2"
[116] Copyright 1995-2009 by Chester Ramey.
[119] Et pendant que vous y êtes, pensez à remédier au problème bien connu du piped read.