Le répertoire /dev contient des entrées pour les périphériques physiques qui pourraient être présent sur votre système. [1] Les partitions du disque dur contenant les systèmes de fichiers montés ont des entrées dans /dev, comme un simple df le montre.
bash$ df Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda6 495876 222748 247527 48% / /dev/hda1 50755 3887 44248 9% /boot /dev/hda8 367013 13262 334803 4% /home /dev/hda5 1714416 1123624 503704 70% /usr |
Entre autre choses, le répertoire /dev contient aussi des périphériques loopback, tels que /dev/loop0. Un périphérique loopback est une astuce qui permet à un fichier ordinaire d'être accédé comme si il était un périphérique bloc. [2] Ceci rend possible le montage d'un système de fichier entier en un seul gros fichier. Voir Exemple 13-6 et Exemple 13-5.
Quelques pseudo-périphériques dans /dev ont d'autres utilisations spécialisées, telles que /dev/null, /dev/zero et /dev/urandom.
[1] | Les entrées dans /dev fournissent des points de montage pour les périphériques physiques et virtuels. Ces entrées utilisent très peu d'espace disque. Quelques périphériques, tels que /dev/null, /dev/zero, et /dev/urandom sont virtuels. Ce ne sont pas des périphériques physiques et ils existent seulement au niveau logiciel. |
[2] | Un périphérique bloc lit et/ou écrit des données par morceaux, ou blocs en constraste avec un périphérique caractère, qui accède aux données caractère par caractère. Des exemples de périphérique bloc sont un disque dur et un lecteur CD ROM. Un exemple de périphérique caractère est un clavier. |
Précédent | Sommaire | Suivant |
/dev et /proc | Niveau supérieur | /proc |
La commande declare permet d'assigner une valeur à une variable dans la même déclaration que celle de ses ses propriétés.
Exemple 9-20. Utiliser declare pour typer des variables
#!/bin/bash fonc1 () { echo Ceci est une fonction. } declare -f # Liste la fonction ci-dessus. echo declare -i var1 # var1 est un entier. var1=2367 echo "var1 déclaré comme $var1" var1=var1+1 # La déclaration d'un entier élimine le besoin d'utiliser let. echo "var1 incrémenté par 1 vaut $var1." # Essai de modification de la variable déclarée comme entier echo "Essai de modification de var1 en une valeur flottante, 2367.1." var1=2367.1 # Résultat: un message d'erreur, et une variable non modifiée. echo "var1 vaut toujours $var1" echo declare -r var2=13.36 # 'declare' permet de configurer une variable #+ proprement et de lui affecter une valeur. echo "var2 déclaré comme $var2" # Essai de modification d'une valeur en lecture #+ seule. var2=13.37 # Génère un message d'erreur, et sort du script. echo "var2 vaut toujours $var2" # Cette ligne ne s'exécutera pas. exit 0 # Le script ne terminera pas ici. |
Précédent | Sommaire | Suivant |
Substitution des paramètres | Niveau supérieur | Références indirectes aux variables |
#!/bin/bash # assert.sh assert () # Si la condition est fausse, { #+ sort du script avec un message d'erreur. E_PARAM_ERR=98 E_ASSERT_FAILED=99 if [ -z "$2" ] # Pas assez de paramètres passés. then return $E_PARAM_ERR # Pas de dommages. fi noligne=$2 if [ ! $1 ] then echo "Mauvaise assertion: \"$1\"" echo "Fichier \"$0\", ligne $noligne" exit $E_ASSERT_FAILED # else (sinon) # return (retour) # et continue l'exécution du script. fi } a=5 b=4 condition="$a -lt $b" # Message d'erreur et sortie du script. # Essayer de configurer la "condition" en autre chose #+ et voir ce qui se passe. assert "$condition" $LINENO # Le reste du script s'exécute si assert n'échoue pas. # Quelques commandes. # ... echo "Cette instruction s'exécute seulement si \"assert\" n'échoue pas." # ... # Quelques commandes de plus. exit 0
piéger la sortie.
La commande exit d'un script déclenche un signal 0, terminant le processus, c'est-à-dire le script lui-même. [2] Il est souvent utilisé pour récupérer la main lors de exit, en forçant un << affichage >> des variables, par exemple. Le trap doit être la première commande du script.
Spécifie une action à la réception d'un signal; aussi utile pour le déboguage.
trap '' 2 # Ignore l'interruption 2 (Control-C), sans action définie. trap 'echo "Control-C désactivé."' 2 # Message lorsque Control-C est utilisé. |
Exemple 30-5. Récupérer la sortie
#!/bin/bash trap 'echo Liste de Variables --- a = $a b = $b' EXIT # EXIT est le nom du signal généré en sortie d'un script. a=39 b=36 exit 0 # Notez que mettre en commentaire la commande 'exit' ne fait aucune différence, # car le script sort dans tous les cas après avoir exécuté les commandes. |
Exemple 30-6. Nettoyage après un Control-C
#!/bin/bash # logon.sh: Un script rapide mais sale pour vérifier si vous êtes déjà connecté. VRAI=1 JOURNAL=/var/log/messages # Notez que $JOURNAL doit être lisible (chmod 644 /var/log/messages). FICHIER_TEMPORAIRE=temp.$$ # Crée un fichier temporaire "unique", en utilisant l'identifiant du processus. MOTCLE=adresse # A la connexion, la ligne "remote IP address xxx.xxx.xxx.xxx" # ajoutée à /var/log/messages. ENLIGNE=22 INTERRUPTION_UTILISATEUR=13 VERIFIE_LIGNES=100 # Nombre de lignes à vérifier dans le journal. trap 'rm -f $FICHIER_TEMPORAIRE; exit $INTERRUPTION_UTILISATEUR' TERM INT # Nettoie le fichier temporaire si le script est interrompu avec control-c. echo while [ $VRAI ] # Boucle sans fin. do tail -$VERIFIE_LIGNES $JOURNAL> $FICHIER_TEMPORAIRE # Sauve les 100 dernières lignes du journal dans un fichier temporaire. # Nécessaire, car les nouveaux noyaux génèrent beaucoup de messages lors de la # connexion. search=`grep $MOTCLE $FICHIER_TEMPORAIRE` # Vérifie la présence de la phrase "IP address", # indiquant une connexion réussie. if [ ! -z "$search" ] # Guillemets nécessaires à cause des espaces possibles. then echo "En ligne" rm -f $FICHIER_TEMPORAIRE # Suppression du fichier temporaire. exit $ENLIGNE else echo -n "." # l'option -n supprime les retours à la ligne de echo, # de façon à obtenir des lignes de points continues. fi sleep 1 done # Note: Si vous modifiez la variable MOTCLE par "Exit", # ce script peut être utilisé lors de la connexion pour vérifier une déconnexion # inattendue. # Exercice: Modifiez le script, suivant la note ci-dessus, et embellissez-le. exit 0 # Nick Drage suggère une autre méthode. while true do ifconfig ppp0 | grep UP 1> /dev/null && echo "connecté" && exit 0 echo -n "." # Affiche des points (.....) jusqu'au moment de la connexion. sleep 2 done # Problème: Appuyer sur Control-C pour terminer ce processus peut être # insuffisant (des points pourraient toujours être affichés). # Exercice: Corrigez ceci. # Stephane Chazelas a lui-aussi suggéré une autre méthode. CHECK_INTERVAL=1 while ! tail -1 "$JOURNAL" | grep -q "$MOTCLE" do echo -n . sleep $CHECK_INTERVAL done echo "On-line" # Exercice: Discutez les avantages et inconvénients de chacune des méthodes. |
![]() | trap '' SIGNAL (deux apostrophes adjacentes) désactive SIGNAL pour le reste du script. trap SIGNAL restaure la fonctionnalité de SIGNAL. C'est utile pour protéger une portion critique d'un script d'une interruption indésirable. |
trap '' 2 # Le signal 2 est Control-C, maintenant désactivé. command command command trap 2 # Réactive Control-C |
[1] | Le débogueur Bash de Rocky Bernstein comble légèrement ce manque. |
[2] | Par convention, signal 0 est affecté à exit. |
Précédent | Sommaire | Suivant |
Des Zéros et des Nulls | Niveau supérieur | Options |
Exemple A-12. Fichier de données pour le << Jeu de la Vie >>
# This is an example "generation 0" start-up file for "life.sh". # -------------------------------------------------------------- # The "gen0" file is a 10 x 10 grid using a period (.) for live cells, #+ and an underscore (_) for dead ones. We cannot simply use spaces #+ for dead cells in this file because of a peculiarity in Bash arrays. # [Exercise for the reader: explain this.] # # Lines beginning with a '#' are comments, and the script ignores them. __.__..___ ___._.____ ____.___.. _._______. ____._____ ..__...___ ____._____ ___...____ __.._..___ _..___..__ |
+++
Les deux scripts suivants sont de Mark Moraes de l'Université de Toronto. Voir le fichier joint << Moraes-COPYRIGHT >> pour les permissions et restrictions.
Exemple A-13. behead: Supprimer les en-têtes des courriers électroniques et des nouvelles
#! /bin/sh # Supprime l'entête d'un message mail/news jusqu'à la première ligne vide. # Mark Moraes, Université de Toronto # ==> Ces commentaires sont ajoutés par l'auteur de ce document. if [ $# -eq 0 ]; then # ==> Si pas d'arguments en ligne de commande, alors fonctionne avec un # ==> fichier redirigé vers stdin. sed -e '1,/^$/d' -e '/^[ ]*$/d' # --> Supprime les lignes vides et les autres jusqu'à la première # --> commençant avec un espace blanc. else # ==> Si des arguments sont présents en ligne de commande, alors fonctionne avec # ==> des fichiers nommés. for i do sed -e '1,/^$/d' -e '/^[ ]*$/d' $i # --> De même. done fi # ==> Exercice: Ajouter la vérification d'erreurs et d'autres options. # ==> # ==> Notez que le petit script sed se répère à l'exception des arguments # ==> passés. # ==> Est-il intéressant de l'embarquer dans une fonction? Pourquoi? |
Exemple A-14. ftpget: Télécharger des fichiers via ftp
#! /bin/sh # $Id: ftpget.sh,v 1.2 2003/11/02 17:21:35 guillaume Exp $ # Script pour réaliser une suite d'actions avec un ftp anonyme. Généralement, # convertit une liste d'arguments de la ligne de commande en entrée vers ftp. # Simple et rapide - écrit comme compagnon de ftplist # -h spécifie l'hôte distant (par défaut prep.ai.mit.edu) # -d spécifie le répertoire distant où se déplacer - vous pouvez spécifier une # séquence d'options -d - elles seront exécutées chacune leur tour. Si les # chemins sont relatifs, assurez-vous d'avoir la bonne séquence. Attention aux # chemins relatifs, il existe bien trop de liens symboliques de nos jours. # (par défaut, le répertoire au moment de la connexion) # -v active l'option verbeux de ftp et affiche toutes les réponses du serveur # ftp # -f fichierdistant[:fichierlocal] récupère le fichier distant et le renomme en # localfile # -m modele fait un mget suivant le modèle spécifié. Rappelez-vous de mettre # entre guillemets les caractères shell. # -c fait un cd local vers le répertoire spécifié # Par exemple example, # ftpget -h expo.lcs.mit.edu -d contrib -f xplaces.shar:xplaces.sh \ # -d ../pub/R3/fixes -c ~/fixes -m 'fix*' # récupèrera xplaces.shar à partir de ~ftp/contrib sur expo.lcs.mit.edu et # l'enregistrera sous xplaces.sh dans le répertoire actuel, puis obtiendra # tous les correctifs de ~ftp/pub/R3/fixes en les plaçant sous le répertoire # ~/fixes. # De façon évidente, la séquence des options est importante, car les commandes # équivalentes sont exécutées par ftp dans le même ordre. # # Mark Moraes (moraes@csri.toronto.edu), Feb 1, 1989 # ==> Les signes inférieur et supérieur ont été modifiés par des "parens" pour # ==> éviter des soucis avec DocBook. # # ==> Ces commentaires ont été ajoutés par l'auteur de ce document. # PATH=/local/bin:/usr/ucb:/usr/bin:/bin # export PATH # ==> Les deux lignes ci-dessus faisaient parti du script original et étaient # ==> probablement inutiles FICHIER_TEMPORAIRE=/tmp/ftp.$$ # ==> Crée un fichier temporaire, en utilisant l'identifiant du processus du # ==> script ($$) pour construire le nom du fichier. SITE=`domainname`.toronto.edu # ==> 'domainname' est similaire à 'hostname' # ==> Ceci pourrait être réécrit en ajoutant un paramètre ce qui rendrait son # ==> utilisation plus générale. usage="Usage: $0 [-h hotedisrant] [-d repertoiredistant]... [-f fichierdistant:fichierlocal]... \ [-c repertoirelocal] [-m modele] [-v]" optionsftp="-i -n" verbflag= set -f # So we can use globbing in -m set x `getopt vh:d:c:m:f: $*` if [ $? != 0 ]; then echo $usage exit 65 fi shift trap 'rm -f ${FICHIER_TEMPORAIRE} ; exit' 0 1 2 3 15 echo "user anonymous ${USER-gnu}@${SITE} > ${FICHIER_TEMPORAIRE}" # ==> Ajout des guillemets (recommendé pour les echo complexes). echo binary >> ${FICHIER_TEMPORAIRE} for i in $* # ==> Analyse les arguments de la ligne de commande. do case $i in -v) verbflag=-v; echo hash >> ${FICHIER_TEMPORAIRE}; shift;; -h) hotedistant=$2; shift 2;; -d) echo cd $2 >> ${FICHIER_TEMPORAIRE}; if [ x${verbflag} != x ]; then echo pwd >> ${FICHIER_TEMPORAIRE}; fi; shift 2;; -c) echo lcd $2 >> ${FICHIER_TEMPORAIRE}; shift 2;; -m) echo mget "$2" >> ${FICHIER_TEMPORAIRE}; shift 2;; -f) f1=`expr "$2" : "\([^:]*\).*"`; f2=`expr "$2" : "[^:]*:\(.*\)"`; echo get ${f1} ${f2} >> ${FICHIER_TEMPORAIRE}; shift 2;; --) shift; break;; esac done if [ $# -ne 0 ]; then echo $usage exit 65 # ==> Modifier de l'"exit 2" pour se conformer avec le standard. fi if [ x${verbflag} != x ]; then optionsftp="${optionsftp} -v" fi if [ x${hotedistant} = x ]; then hotedistant=prep.ai.mit.edu # ==> A réécrire pour utiliser votre site ftp favori. fi echo quit >> ${FICHIER_TEMPORAIRE} # ==> Toutes les commandes sont sauvegardées dans fichier_temporaire. ftp ${optionsftp} ${hotedistant} < ${FICHIER_TEMPORAIRE} # ==> Maintenant, exécution par ftp de toutes les commandes contenues dans le # ==> fichier fichier_temporaire. rm -f ${FICHIER_TEMPORAIRE} # ==> Enfin, fichier_temporaire est supprimé (vous pouvez souhaiter le copier # ==> dans un journal). # ==> Exercices: # ==> --------- # ==> 1) Ajouter une vérification d'erreurs. # ==> 2) Ajouter des tas de trucs. |
+
Antek Sawicki a contribué avec le script suivant, qui fait une utilisation très intelligente des opérateurs de substitution de paramètres discutés dans la Section 9.3.
Exemple A-15. password: Générer des mots de passe aléatoires de 8 caractères
#!/bin/bash # Pourrait avoir besoin d'être appelé avec un #!/bin/bash2 sur les anciennes #+ machines. # # Générateur de mots de passe aléatoires pour bash 2.x #+ par Antek Sawicki <tenox@tenox.tc>, # qui a généreusement permis à l'auteur de ce document de l'utiliser ici. # # ==> Commentaires ajoutés par l'auteur du document ==> MATRICE="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" LONGUEUR="8" # ==> Modification possible de 'LONGUEUR' pour des mots de passe plus longs. while [ "${n:=1}" -le "$LONGUEUR" ] # ==> Rappelez-vous que := est l'opérateur de "substitution par défaut". # ==> Donc, si 'n' n'a pas été initialisé, l'initialisez à 1. do PASS="$PASS${MATRICE:$(($RANDOM%${#MATRICE})):1}" # ==> Très intelligent, pratiquement trop astucieux. # ==> Commençons par le plus intégré... # ==> ${#MATRICE} renvoie la longueur du tableau MATRICE. # ==> $RANDOM%${#MATRICE} renvoie un nombre aléatoire entre 1 et la # ==> longueur de MATRICE - 1. # ==> ${MATRICE:$(($RANDOM%${#MATRICE})):1} # ==> renvoie l'expansion de MATRICE à une position aléatoire, par # ==> longueur 1. # ==> Voir la substitution de paramètres {var:pos:len}, section 3.3.1 # ==> et les exemples suivants. # ==> PASS=... copie simplement ce résultat dans PASS (concaténation). # ==> Pour mieux visualiser ceci, décommentez la ligne suivante # ==> echo "$PASS" # ==> pour voir la construction de PASS, un caractère à la fois, # ==> à chaque itération de la boucle. let n+=1 # ==> Incrémentez 'n' pour le prochain tour. done echo "$PASS" # ==> Ou, redirigez le fichier, comme voulu. exit 0 |
+
James R. Van Zandt a contribué avec ce script, qui utilise les tubes nommés et, ce sont ses mots, << really exercises quoting and escaping >>.
Exemple A-16. fifo: Faire des sauvegardes journalières, en utilisant des tubes nommés
#!/bin/bash # ==> Script de James R. Van Zandt, et utilisé ici avec sa permission. # ==> Commentaires ajoutés par l'auteur de ce document. ICI=`uname -n` # ==> nom d'hôte LA_BAS=bilbo echo "début de la sauvegarde distabte vers $LA_BAS à `date +%r`" # ==> `date +%r` renvoie l'heure en un format sur 12 heures, par exempe # ==> "08:08:34 PM". # Assurez-vous que /pipe est réellement un tube et non pas un fichier #+ standard. rm -rf /tube mkfifo /tube # ==> Crée un fichier "tube nommé", nommé "/tube". # ==> 'su xyz' lance les commandes en tant qu'utilisateur "xyz". # ==> 'ssh' appele le shell sécurisé (client de connexion à distance). su xyz -c "ssh $LA_BAS \"cat >/home/xyz/sauve/${ICI}-jour.tar.gz\" < /tube"& cd / tar -czf - bin boot dev etc home info lib man root sbin share usr var >/tube # ==> Utilise un tube nommé, /tube, pour communiquer entre processus: # ==> 'tar/gzip' écrit dans le tube et 'ssh' lit /tube. # ==> Le résultat final est que cela sauvegarde les répertoires principaux; #+ ==> à partir de /. # ==> Quels sont les avantages d'un "tube nommé" dans cette situation, # ==> en opposition avec le "tube anonyme", avec |? # ==> Est-ce qu'un tube anonyme pourrait fonctionner ici? exit 0 |
+
Stephane Chazelas a contribué avec le script suivant pour démontrer que générer des nombres aléatoires ne requiert pas de tableaux.
Exemple A-17. primes: Générer des nombres aléatoires en utilisant l'opérateur modulo
#!/bin/bash # primes.sh: Génère des nombres premiers, sans utiliser des tableaux. # Script contribué par Stephane Chazelas. # Il n'utilise *pas* l'algorithme classique "Sieve of Eratosthenes", #+ mais utilise à la palce la méthode plus intuitive de test de chaque nombre #+ candidat pour les facteurs (diviseurs), en utilisant l'opérateur modulo "%". LIMITE=1000 # Premiers de 2 à 1000 Premiers() { (( n = $1 + 1 )) # Va au prochain entier. shift # Prochain paramètre dans la liste. # echo "_n=$n i=$i_" if (( n == LIMITE )) then echo $* return fi for i; do # "i" est initialisé à "@", les précédentes #+ valeurs de $n. # echo "-n=$n i=$i-" (( i * i > n )) && break # Optimisation. (( n % i )) && continue # Passe les non premiers en utilisant l'opérateur #+ modulo. Premiers $n $@ # Récursion à l'intérieur de la boucle. return done Premiers $n $@ $n # Récursion à l'extérieur de la boucle. # Accumule successivement les paramètres de #+ position. # "$@" est la liste des premiers accumulés. } Premiers 1 exit 0 # Décommenter les lignes 17 et 25 pour vous aider à comprendre ce qui se passe. # Comparez la vitesse de cet algorithme de génération des nombres premiers avec # celui de "Sieve of Eratosthenes" (ex68.sh). # Exercice: Réécrivez ce script sans récursion, pour une exécution plus rapide. |
+
Jordi Sanfeliu a donné sa permission pour utiliser son élégant script sur les arborescences.
Exemple A-18. tree: Afficher l'arborescence d'un répertoire
#!/bin/sh # @(#) tree 1.1 30/11/95 by Jordi Sanfeliu # email: mikaku@arrakis.es # # Version initiale : 1.0 30/11/95 # Prochaine version: 1.1 24/02/97 Maintenant avec des liens symboliques # Corrigé par : Ian Kjos, pour supporter les répertoires non dispo # email: beth13@mail.utexas.edu # # Tree est un outil pour visualiser la hiérarchie d'un répertoire # # ==> Le script 'Tree' utilisé ici avec la permission de son auteur, Jordi Sanfeliu. # ==> Commentaires ajoutés par l'auteur de ce document. # ==> Ajout des guillemets pour les arguments. search () { for dir in `echo *` # ==> `echo *` affiche tous les fichiers du répertoire actuel sans retour à # ==> la ligne. # ==> Même effet que for dir in * # ==> mais "dir in `echo *`" ne gère pas les noms de fichiers comprenant des # ==> espaces blancs. do if [ -d "$dir" ] ; then # ==> S'il s'agit d'un répertoire (-d)... zz=0 # ==> Variable temporaire, pour garder trace du niveau de # ==> répertoire. while [ $zz != $deep ] # Conserve la trace de la boucle interne. do echo -n "| " # ==> Affiche le symbôle du connecteur vertical # ==> avec 2 espaces mais pas de retour à la ligne # ==> pour l'indentation. zz=`expr $zz + 1` # ==> Incrémente zz. done if [ -L "$dir" ] ; then # ==> Si le répertoire est un lien symbolique... echo "+---$dir" `ls -l $dir | sed 's/^.*'$dir' //'` # ==> Affiche le connecteur horizontal et affiche le nom du # ==> répertoire mais... # ==> supprime la partie date/heure. else echo "+---$dir" # ==> Affiche le symbole du connecteur # ==> horizontal et le nom du répertoire. if cd "$dir" ; then # ==> S'il peut se déplacer dans le sous-répertoire... deep=`expr $deep + 1` # ==> Incrémente la profondeur. search # avec la récursivité ;-) # ==> La fonction s'appelle elle-même. numdirs=`expr $numdirs + 1` # ==> Incrémente le compteur de # ==> répertoires. fi fi fi done cd .. # ==> Se placer un niveau au-dessus. if [ "$deep" ] ; then # ==> Si la profondeur est nulle (renvoie TRUE)... swfi=1 # ==> initialiser l'indicateur indiquant que la # ==> recherche est terminée. fi deep=`expr $deep - 1` # ==> Décrémente la profondeur. } # - Principal - if [ $# = 0 ] ; then cd `pwd` # ==> Pas d'arguments au script, alors utilise le répertoire actuel. else cd $1 # ==> Sinon, va dans le répertoire indiqué. fi echo "Répertoire initial = `pwd`" swfi=0 # ==> Indicateur de terminaison. deep=0 # ==> Profondeur de la liste. numdirs=0 zz=0 while [ "$swfi" != 1 ] # Tant que l'indicateur n'est pas initialisé do search # ==> Appelle la fonctione après avoir initialisé les variables. done echo "Nombre total de répertoires = $numdirs" exit 0 # ==> Challenge: essayez de comprendre comment fonctionne ce script |
+
Noah Friedman a donné sa permission pour utiliser son script contenant des fonctions sur les chaînes de caractères, qui reproduit les fonctions de manipulations de la bibliothèque C string.
Exemple A-19. string: Manipuler les chaînes de caractères comme en C
#!/bin/bash # string.bash --- bash emulation of string(3) library routines # Author: Noah Friedman <friedman@prep.ai.mit.edu> # ==> Used with his kind permission in this document. # Created: 1992-07-01 # Last modified: 1993-09-29 # Public domain # Conversion to bash v2 syntax done by Chet Ramey # Commentary: # Code: #:docstring strcat: # Usage: strcat s1 s2 # # Strcat appends the value of variable s2 to variable s1. # # Example: # a="foo" # b="bar" # strcat a b # echo $a # => foobar # #:end docstring: ###;;;autoload ==> Autoloading of function commented out. function strcat () { local s1_val s2_val s1_val=${!1} # indirect variable expansion s2_val=${!2} eval "$1"=\'"${s1_val}${s2_val}"\' # ==> eval $1='${s1_val}${s2_val}' avoids problems, # ==> if one of the variables contains a single quote. } #:docstring strncat: # Usage: strncat s1 s2 $n # # Line strcat, but strncat appends a maximum of n characters from the value # of variable s2. It copies fewer if the value of variabl s2 is shorter # than n characters. Echoes result on stdout. # # Example: # a=foo # b=barbaz # strncat a b 3 # echo $a # => foobar # #:end docstring: ###;;;autoload function strncat () { local s1="$1" local s2="$2" local -i n="$3" local s1_val s2_val s1_val=${!s1} # ==> indirect variable expansion s2_val=${!s2} if [ ${#s2_val} -gt ${n} ]; then s2_val=${s2_val:0:$n} # ==> substring extraction fi eval "$s1"=\'"${s1_val}${s2_val}"\' # ==> eval $1='${s1_val}${s2_val}' avoids problems, # ==> if one of the variables contains a single quote. } #:docstring strcmp: # Usage: strcmp $s1 $s2 # # Strcmp compares its arguments and returns an integer less than, equal to, # or greater than zero, depending on whether string s1 is lexicographically # less than, equal to, or greater than string s2. #:end docstring: ###;;;autoload function strcmp () { [ "$1" = "$2" ] && return 0 [ "${1}" '<' "${2}" ] > /dev/null && return -1 return 1 } #:docstring strncmp: # Usage: strncmp $s1 $s2 $n # # Like strcmp, but makes the comparison by examining a maximum of n # characters (n less than or equal to zero yields equality). #:end docstring: ###;;;autoload function strncmp () { if [ -z "${3}" -o "${3}" -le "0" ]; then return 0 fi if [ ${3} -ge ${#1} -a ${3} -ge ${#2} ]; then strcmp "$1" "$2" return $? else s1=${1:0:$3} s2=${2:0:$3} strcmp $s1 $s2 return $? fi } #:docstring strlen: # Usage: strlen s # # Strlen returns the number of characters in string literal s. #:end docstring: ###;;;autoload function strlen () { eval echo "\${#${1}}" # ==> Returns the length of the value of the variable # ==> whose name is passed as an argument. } #:docstring strspn: # Usage: strspn $s1 $s2 # # Strspn returns the length of the maximum initial segment of string s1, # which consists entirely of characters from string s2. #:end docstring: ###;;;autoload function strspn () { # Unsetting IFS allows whitespace to be handled as normal chars. local IFS= local result="${1%%[!${2}]*}" echo ${#result} } #:docstring strcspn: # Usage: strcspn $s1 $s2 # # Strcspn returns the length of the maximum initial segment of string s1, # which consists entirely of characters not from string s2. #:end docstring: ###;;;autoload function strcspn () { # Unsetting IFS allows whitspace to be handled as normal chars. local IFS= local result="${1%%[${2}]*}" echo ${#result} } #:docstring strstr: # Usage: strstr s1 s2 # # Strstr echoes a substring starting at the first occurrence of string s2 in # string s1, or nothing if s2 does not occur in the string. If s2 points to # a string of zero length, strstr echoes s1. #:end docstring: ###;;;autoload function strstr () { # if s2 points to a string of zero length, strstr echoes s1 [ ${#2} -eq 0 ] && { echo "$1" ; return 0; } # strstr echoes nothing if s2 does not occur in s1 case "$1" in *$2*) ;; *) return 1;; esac # use the pattern matching code to strip off the match and everything # following it first=${1/$2*/} # then strip off the first unmatched portion of the string echo "${1##$first}" } #:docstring strtok: # Usage: strtok s1 s2 # # Strtok considers the string s1 to consist of a sequence of zero or more # text tokens separated by spans of one or more characters from the # separator string s2. The first call (with a non-empty string s1 # specified) echoes a string consisting of the first token on stdout. The # function keeps track of its position in the string s1 between separate # calls, so that subsequent calls made with the first argument an empty # string will work through the string immediately following that token. In # this way subsequent calls will work through the string s1 until no tokens # remain. The separator string s2 may be different from call to call. # When no token remains in s1, an empty value is echoed on stdout. #:end docstring: ###;;;autoload function strtok () { : } #:docstring strtrunc: # Usage: strtrunc $n $s1 {$s2} {$...} # # Used by many functions like strncmp to truncate arguments for comparison. # Echoes the first n characters of each string s1 s2 ... on stdout. #:end docstring: ###;;;autoload function strtrunc () { n=$1 ; shift for z; do echo "${z:0:$n}" done } # provide string # string.bash ends here # ========================================================================== # # ==> Everything below here added by the document author. # ==> Suggested use of this script is to delete everything below here, # ==> and "source" this file into your own scripts. # strcat string0=one string1=two echo echo "Testing \"strcat\" function:" echo "Original \"string0\" = $string0" echo "\"string1\" = $string1" strcat string0 string1 echo "New \"string0\" = $string0" echo # strlen echo echo "Testing \"strlen\" function:" str=123456789 echo "\"str\" = $str" echo -n "Length of \"str\" = " strlen str echo # Exercise: # -------- # Add code to test all the other string functions above. exit 0 |
+
+
Stephane Chazelas montre la programmation objet dans un script Bash.
Exemple A-20. obj-oriented: Bases de données orientées objet
#!/bin/bash # obj-oriented.sh: programmation orienté objet dans un script shell. # Script par Stephane Chazelas. person.new() # Ressemble à la déclaration d'une classe en C++. { local nom_objet=$1 nom=$2 prenom=$3 datenaissance=$4 eval "$nom_objet.set_nom() { eval \"$nom_objet.get_nom() { echo \$1 }\" }" eval "$nom_objet.set_prenom() { eval \"$nom_objet.get_prenom() { echo \$1 }\" }" eval "$nom_objet.set_datenaissance() { eval \"$nom_objet.get_datenaissance() { echo \$1 }\" eval \"$nom_objet.show_datenaissance() { echo \$(date -d \"1/1/1970 0:0:\$1 GMT\") }\" eval \"$nom_objet.get_age() { echo \$(( (\$(date +%s) - \$1) / 3600 / 24 / 365 )) }\" }" $nom_objet.set_nom $nom $nom_objet.set_prenom $prenom $nom_objet.set_datenaissance $datenaissance } echo person.new self Bozeman Bozo 101272413 # Crée une instance de "person.new" (en fait, passe les arguments à la #+ fonction). self.get_prenom # Bozo self.get_nom # Bozeman self.get_age # 28 self.get_datenaissance # 101272413 self.show_datenaissance # Sat Mar 17 20:13:33 MST 1973 echo # typeset -f # pour voir les fonctions créées (attention, cela fait défiler la page). exit 0 |