Guide avancé d'écriture des scripts Bash: | ||
---|---|---|
Précédent | Chapitre 12. Filtres externes, programmes et commandes | Suivant |
Commandes pour utilisateurs plus expérimentés
-exec COMMANDE \;
Effectue COMMANDE sur chaque fichier trouvé par find. La séquence de commandes se termine par un \; (le << ; >> est échappé pour être certain que le shell le passe de façon litéralle à find). Si COMMANDE contient {}, alors find substitue le chemin complet du fichier en cours à << {} >>.
bash$ find ~/ -name '*.txt' /home/bozo/.kde/share/apps/karm/karmdata.txt /home/bozo/misc/irmeyc.txt /home/bozo/test-scripts/1.txt |
find /home/bozo/projects -mtime 1 # Liste tous les fichiers situés dans le répertoire /home/bozo/projects #+ qui ont été modifiés il y a, au plus tard, 24 heures. # # mtime = date de dernière modification du fichier cible # ctime = date de dernier changement d'état (via 'chmod' ou autre) # atime = date du dernier accès REP=/home/bozo/junk_files find "$REP" -type f -atime +5 -exec rm {} \; # Efface tous les fichiers contenu dans "/home/bozo/fichiers_bidons" #+ qui n'ont pas été accédés depuis au moins 5 jours. # # "-type typefichier", où # f = fichier classique # d = répertoire, etc. # (La page de manuel 'find' en a une liste complète.) |
find /etc -exec grep '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \; # Trouve toutes les adresses IP (xxx.xxx.xxx.xxx) contenues dans les fichiers #+ situés dans le répertoire /etc . # Quelques correspondances n'auront rien à voir - comment peuvent-elles être #+ éliminées ? # Peut-être en faisant: find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \ | grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$' # [:digit:] est un ensemble de caractères POSIX 1003.2 # introduit avec le standard POSIX 1003.2. # Merci, S.C. |
![]() | L'option -exec de find ne doit pas être confondue avec la commande intégrée du shellexec. |
Exemple 12-2. incorrectname élimine dans le répertoire courant les fichiers dont le nom contient des caractères incorrects et des espaces blancs.
#!/bin/bash # Efface les fichiers du répertoire courant contenant des mauvais caractères. for nomfichier in * do mauvaisnom=`echo "$nomfichier" | sed -n /[\+\{\;\"\\\=\?~\(\)\<\>\&\*\|\$]/p` # Les fichiers contenant ces méchants: + { ; " \ = ? ~ ( ) < > & * | $ rm $mauvaisnom 2>/dev/null # Les erreurs sont effacées. done # Maintenant, faire attention aux noms de fichiers contenant des espaces blancs. find . -name "* *" -exec rm -f {} \; # Le chemin du fichier trouvé par "find" remplace "{}". # Le '\' nous assure que le ';' est interprété litérallement, en tant que fin #+ de commande. exit 0 #--------------------------------------------------------------------- # Les commandes ci-dessous ne seront pas éxécutées à cause de la commande # "exit" au dessus. # Voici une alternative au script ci-dessus: find . -name '*[+{;"\\=?~()<>&*|$ ]*' -exec rm -f '{}' \; exit 0 # (Merci, S.C.) |
Exemple 12-3. Effacer un fichier par son numéro d'inode
#!/bin/bash # idelete.sh: Effacer un fichier grâce à son inode. # C'est très utile quand un nom de fichier commence avec un caractère illégal, #+ comme un ? ou -. NBARGS=1 # L'argument du nom de fichier doit être passé au script. E_MAUVAISARGS=70 E_FICHIER_INEXISTANT=71 E_CHANGE_D_ESPRIT=72 if [ $# -ne "$NBARGS" ] then echo "Usage: `basename $0` nomfichier" exit $E_MAUVAISARGS fi if [ ! -e "$1" ] then echo "Le fichier \""$1"\" n'existe pas." exit $E_FICHIER_INEXISTANT fi inum=`ls -i | grep "$1" | awk '{print $1}'` # inum = inode (NdT; index node) numéro de fichier # Chaque fichier possède une inode, qui contient ses informations d'adresses #+ physiques. echo; echo -n "Effacer vraiment \"$1\" (o/n)? " # L'option '-v' de 'rm' pose la même question. read reponse case "$reponse" in [nN]) echo "Vous avez changé d'avis" exit $E_CHANGE_D_ESPRIT ;; *) echo "Effacement en cours du \"$1\".";; esac find . -inum $inum -exec rm {} \; echo "Fichier "\"$1"\" effacé!" exit 0 |
Voir Exemple 12-22, Exemple 3-4 et Exemple 10-9 pour des exemples de scripts utilisant find. La page de manuel de cette commande, complexe et puissante, apporte des détails supplémentaires.
Un filtre qui sert à passer des paramètres à une commande, et aussi un outil pour réunir les commandes elles-mêmes. Il découpe un flux de données en des morceaux suffisament petits pour laisser les filtres et les commandes opérer. Considérez-le comme une puissante alternative aux guillemets inversés. Dans les situations où les guillemets inversés échouent avec une erreur "too many arguments" (trop d'arguments), substituer xargs règle souvent les problèmes. Habituellement, xargs lit depuis stdin ou depuis un tube mais il accèpte aussi de lire dans la sortie d'un fichier.
La commande par défaut d'xargs est echo. Cela signifie que tout flux entrant transmis via un tube vers xargs peut voir ses sauts de ligne et caractères d'espacements supprimés.
bash$ ls -l total 0 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 fichier1 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 fichier2 bash$ ls -l | xargs total 0 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 fichier1 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 fichier2 |
ls | xargs -p -l gzip Compresse avec gzip tous les fichiers du répertoire courant, un par un, et demande confirmation avant chaque opération.
![]() | Une option d'xargs intéressante est -n NN, qui limite à NN le nombre d'arguments passés. ls | xargs -n 8 echo affiche le contenu du répertoire courant sur 8 colonnes. |
![]() | Une autre option utile est -0, combinée avec find -print0 ou grep -lZ. Ceci permet de manipuler les arguments contenant des espaces ou des quotes. find / -type f -print0 | xargs -0 grep -liwZ GUI | xargs -0 rm -f grep -rliwZ GUI / | xargs -0 rm -f N'importe laquelle des commande ci-dessus effacera tout fichier contenant << GUI >>. (Merci, S.C.) |
Exemple 12-4. Fichier de traces utilisant xargs pour surveiller les logs système
#!/bin/bash # Génère un fichier de traces dans le répertoire courant à partir de la fin de # /var/log/messages. # Note: /var/log/messages doit être lisible par tout le monde si le script # est appelé par un utilisateur simple. # #root chmod 644 /var/log/messages LIGNES=5 ( date; uname -a ) >>fichiertraces # Time and machine name echo --------------------------------------------------------------------- >>fichiertraces tail -$LIGNES /var/log/messages | xargs | fmt -s >>fichiertraces echo >>fichiertraces echo >>fichiertraces exit 0 |
Exemple 12-5. copyrep, copier les fichiers du répertoire courant vers un autre en utilisant xargs
#!/bin/bash # Copie verbeusement tous les fichiers du répertoire courant # dans le répertoire spécifié sur la ligne de commande if [ -z "$1" ] # Quitte si aucun paramètre n'est fourni. then echo "Usage: `basename $0` rep-destination" exit 65 fi ls . | xargs -i -t cp ./{} $1 # C'est la même chose que # cp * $1 # sauf si les fichiers ont des espaces blancs dans leur nom exit 0 |
Evaluateur d'expression : Concatène et évalue les arguments suivant l'opération souhaitée (les arguments doivent être séparés par des espaces). Les opérations peuvent être arithmétiques, comparatives, chaîne de caractères ou logiques.
renvoie 8
renvoie 2
renvoie 15
L'opérateur de multiplication doit être échappé lorsqu'il est utilisé dans une expression arithmétique avec expr.
Incrémente une variable, de la même manière que let y=y+1 et y=$(($y+1)). Ceci est un exemple d'expansion arithmétique.
Extrait une sous-chaîne de caractères de $longueur caractères, en partant de $position.
Exemple 12-6. Utiliser expr
#!/bin/bash # Démonstration des possibilités de 'expr' # ======================================== echo # Opérations Arithmétiques # ------------------------ echo "Opérations Arithmétique" echo a=`expr 5 + 3` echo "5 + 3 = $a" a=`expr $a + 1` echo echo "a + 1 = $a" echo "(incrémentation d'une variable)" a=`expr 5 % 3` # modulo echo echo "5 mod 3 = $a" echo echo # Opérations Logiques # ------------------- # Retourne 1 si vrai, 0 si faux, #+ à l'opposé des conventions de Bash echo "Opérations Logiques" echo x=24 y=25 b=`expr $x = $y` # Test d'égalité. echo "b = $b" # 0 ( $x -ne $y ) echo a=3 b=`expr $a \> 10` echo 'b=`expr $a \> 10`, donc...' echo "If a > 10, b = 0 (faux)" echo "b = $b" # 0 ( 3 ! -gt 10 ) echo b=`expr $a \< 10` echo "If a < 10, b = 1 (vrai)" echo "b = $b" # 1 ( 3 -lt 10 ) echo # Notez l'échappement des opérations. b=`expr $a \<= 3` echo "If a <= 3, b = 1 (vrai)" echo "b = $b" # 1 ( 3 -le 3 ) # Il y a aussi l'opérande "\>=" (plus grand que ou égal à). echo echo # Opérateurs de comparaison # ------------------------- echo "Opérateurs de comparaison" echo a=zipper echo "a is $a" if [ `expr $a = snap` ] # Force la re-évaluation de la variable 'a' then echo "a ne vaut pas 'zipper'" fi echo echo # Opérateur de chaine de caractères # --------------------------------- echo "Opérateur de chaînes de caractères" echo a=1234zipper43231 echo "Voici \"$a\"." # length: longueur de la chaine b=`expr length $a` echo "La taille de \"$a\" est $b." # index: position du premier caractère dans une sous-chaine # qui correspond à un caractère dans la chaine. b=`expr index $a 23` echo "La position du premier \"2\" dans \"$a\" est \"$b\"." # substr: extrait une sous-chaîne, en spécifiant la position de départ et la #+ taille b=`expr substr $a 2 6` echo "sous-chaîne de \"$a\", commençant à la position 2,\ et long de 6 caractère est \"$b\"." # L'attitude par défaut de l'opérateur 'match' est de #+ chercher une occurence à partir ***du début*** de la chaîne. # # utilisation des expressions régulières b=`expr match "$a" '[0-9]*'` # Comptage numérique. echo Le nombre de chiffres au début de \"$a\" est $b. b=`expr match "$a" '\([0-9]*\)'` # Notez que les parenthèses échappées # == == + déclenchent une reconnaissance de sous-chaîne. echo "Les chiffres au début de \"$a\" sont \"$b\"." echo exit 0 |
![]() | L'opérateur : est équivalent à match. Par exemple, b=`expr $a : [0-9]*` est l'équivalent exact de b=`expr match $a [0-9]*` du listing précédent.
|
Cet exemple illustre comment expr utilise les opérateurs groupant appelés parenthèses echappées -- \( ... \) -- en tandem avec une analyse basée sur les expressions régulières pour faire coïncider une sous-chaîne de caractères.
Perl, sed et awk ont des capacités d'analyse de chaînes de caractères très largement supérieures. Une petite sous-routine sed ou awk dans un script (voir Section 34.2) est aussi une bonne alternative à expr.
Voir Section 9.2 pour en savoir plus sur les manipulations des chaînes de caractères.
Précédent | Sommaire | Suivant |
Les commandes basiques | Niveau supérieur | Commandes de date et d'heure |