|
|
Cet article est disponible en: English Castellano Deutsch Francais Nederlands Portugues Turkce |
par Katja and Guido Socher <katja(at)linuxfocusorg,guido(at)linuxfocus.org> L´auteur: Katja est l'éditeur allemand de LinuxFocus. Elle aime Tux, les films, la photographie et la mer. Sa page personnelle se trouve ici. Guido est un vieux fan de Linux. Il apprécie Linux car il est conçu par des gens honnètes et ouverts. C'est d'ailleurs la raison pour laquelle on l'appelle "Logiciel Ouvert"). Sa page personnelle se trouve à linuxfocus.org/~guido. Traduit en Français par: Éric Jullien <ejullien(at)free.fr> Sommaire: |
Résumé:
Nous expliquerons dans cet article comment écrire de petits scripts shell et nous donnerons de nombreux exemples.
#!/bin/shLes caractères #! indiquent au système que l'argument suivant est le programme à utiliser pour exécuter ce fichier. Ici, nous utilisons le shell /bin/sh.
varname=valuePour récupérer la valeur de la variable, il suffit d'écrire le signe dollar devant le nom de la variable :
#!/bin/sh # affecte une valeur a la variable : a="Bonjour le Monde" # affiche le contenu de la variable "a" : echo "La valeur de A est :" echo $aTapez ces lignes dans un éditeur de texte et enregistrez-les sous le nom "premier". Rendez ensuite le script exécutable en tapant chmod +x premier dans un shell et lancez-le par ./premier
La valeur de A est : Bonjour le MondeIl peut arriver qu'il y ait confusion entre les noms de variables et le reste du texte :
num=2 echo "ceci est le $numeme"Ce script ne va pas afficher "ceci est le 2eme" mais "ceci est le " car le shell recherche une variable nommée numeme qui n'a pas de valeur définie. Pour indiquer au shell que nous faisons référence à la variable num il faut utiliser les accolades :
num=2 echo "ceci est le ${num}eme"Cette fois le script affiche ce que nous attendons :
Syntaxe de la commande | But |
---|---|
echo "un texte" | affiche un texte sur l'écran |
ls | liste des fichiers |
wc -l fichier wc -w fichier wc -c fichier |
compte les lignes du fichier, ou compte les mots du fichier, ou compte le nombre de caractères |
cp fichier_source fichier_dest | copie le fichier_source vers le fichier_dest |
mv ancien_nom nouveau_nom | renomme ou déplace le fichier |
rm fichier | efface le fichier |
grep 'pattern' fichier | cherche des
chaînes de caratères dans
un fichier Exemple: grep 'searchstring' file.txt |
cut -c num_colonne fichier | récupère les données issues de
colonnes de textes à largeur fixe. Exemple : récupère les caractères des positions 5 à 9 cut -b5-9 file.txt Ne pas confondre cette commande avec la commande cat, qui a une utilisation totalement différente. |
cat file.txt | écrit le contenu du fichier file.txt sur la sortie standard stdout (qui est par défaut votre écran) |
file fichier | décrit le type de fichier |
read var | attend une frappe de l'utilisateur en entrée et stocke cette valeur dans une variable (var) |
sort file.txt | trie les lignes du fichier file.txt |
uniq, | retire les lignes en double, utilisé parallèlement à
sort, puisque uniq ne retire
que les doublons sur des lignes consécutives. Exemple : sort file.txt | uniq |
expr | pour faire des maths dans le shell Exemple: ajouter 2 et 3 expr 2 "+" 3 |
find | recherche de fichier Exemple : rechercher un nom : find . -name nom_fichier -print Cette commande possède énormément d'options et de possibilités différentes, rendant leur description impossible dans cet article. |
tee | écrit simultanément des données vers stdout (l'écran) et dans un fichier. Elle s'utilise habituellement de cette manière : commande | tee fichier_de_sortie Affiche la sortie de la commande à l'écran et l'écrit dans le fichier_de_sortie. |
basename fichier | retourne le nom du fichier sans le chemin
d'accès. Exemple : basename /bin/tux retourne seulement tux |
dirname fichier | renvoie le nom du répertoire d'un fichier sans préciser le nom de ce
fichier Exemple: dirname /bin/tux retourne /bin |
head fichier | affiche les premières lignes du début d'un fichier. |
tail fichier | affiche les dernières lignes de la fin d'un fichier |
sed | sed est à la base un programme de recherche et de
remplacement . Il lit le texte de
l'entrée standard (depuis un "pipe", par exemple)
et écrit le résultat sur la sortie standard
(stdout, l'écran).
Le modèle à rechercher est
une expression régulière (voir la section
Réferences). Ce modèle de recherche ('pattern') ne doit pas être confondu avec la syntaxe des 'wildcards' du shell. Par exemple, pour remplacer dans un texte la chaîne de caractères linuxfocus par la chaîne LinuxFocus, exécutez : cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file Cette commande remplace la première occurrence de la chaîne linuxfocus par la chaîne LinuxFocus. S'il y a des lignes contenant plusieurs fois la chaîne linuxfocus et que vous vouliez toutes les remplacer, tapez : cat text.file | sed 's/linuxfocus/LinuxFocus/g' > newtext.file |
awk | La plupart du temps, awk est utilisé pour
extraire des blocs d'une ligne de texte.
Le séparateur par défaut est l'espace.
Utilisez l'option -F pour définir un autre
séparateur. cat fichier.txt | awk -F, '{print $1 "," $3 }'Ici, la virgule (,) est utilisée comme séparateur et nous affichons les première et troisième ($1$3) colonnes. Si fichier.txt contient les lignes suivantes : Adam Bor, 34, India Kerry Miller, 22, USALe résultat sera : Adam Bor, India Kerry Miller, USAVous pouvez faire beaucoup plus avec awk mais ce qui précède est l'usage le plus courant. |
grep "hello" file.txt | wc -lCette commande recherche les lignes contenant la chaîne de caractères hello dans le fichier file.txt et compte le nombre de lignes concernées.
find . -mtime -1 -type f -printrecherche tous les fichiers qui ont été modifiés dans les dernières 24 heures ( -mtime -2 aurait signifié 48 heures). Si on veut regrouper tous ces fichiers dans une archive 'tar' (fichier.tar), la syntaxe de la commande tar est :
tar xvf fichier.tar fich1 fich2 ...Au lieu de taper la totalité, vous pouvez combiner ces deux commandes (find et tar) en utilisant les backticks. Tar va alors regrouper tous les fichiers trouvés par find :
#!/bin/sh # Les ticks sont des guillemets simples inversés (`) # et non des guillemets simples (') tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
if ....; then .... elif ....; then .... else .... fiTrès souvent, une commande particulière, appelée test, est utilisée à l'intérieur d'une instruction "if" pour comparer des chaînes de caractères ou tester l'existence d'un fichier, ses permissions,etc.
[ -f "un_fichier" ] : Teste si "un_fichier" est un fichier [ -x "/bin/ls" ] : Teste si "/bin/ls" existe et est exécutable [ -n "$var" ] : Teste si la variable $var n'est pas vide [ "$a" = "$b" ] : Teste si les variables "$a" et "$b" sont égalesExécutez la commande man test et vous obtiendrez la longue liste de tous les opérateurs de test sur les comparaisons et les fichiers.
#!/bin/sh if [ "$SHELL" = "/bin/bash" ]; then echo "Votre shell de login est le bash (bourne again shell)" else echo "Votre shell de login n'est pas bash mais $SHELL" fiLa variable $SHELL contient le nom du shell de login et c'est ce que nous testons ici en la comparant avec la chaîne de caractères "/bin/bash"
[ -f "/etc/shadow" ] && echo "Cet ordinateur utilise les shadow passwords"La syntaxe && peut être utilisée comme un raccourci de l'instruction if. La partie droite de l'instruction est exécutée si la partie gauche est vraie. On peut lire cette instruction comme une instruction "AND" (ET). Ainsi, l'exemple devient : "le fichier /etc/shadow existe ET la commande echo est exécutée". L'opérateur "OR" (OU) (dont le symbole est ||) est également disponible. Voici un exemple :
#!/bin/sh mailfolder=/var/spool/mail/james [ -r "$mailfolder" ] || { echo "Je ne peux pas lire $mailfolder" ; exit 1; } echo "$mailfolder a recu un courrier de :" grep "^From " $mailfolderCe script teste tout d'abord s'il peut lire un mailfolder ("dossier de courrier") précis. Si c'est le cas, il affiche les lignes "From" du dossier. S'il ne peut lire le fichier $mailfolder, alors l'opérateur "OR" entre en action. En bon français, vous liriez cette ligne de code comme "Dossier de courrier lisible ou sortie du programme" Le problème, ici, c'est qu'après OR on ne peut mettre qu'une seule commande, mais il nous en faut deux :
case ... in ...) action ;; esacPrenons un exemple. La commande file peut indiquer le type d'un fichier :
file lf.gzretourne :
lf.gz: gzip compressed data, deflated, original filename, last modified: Mon Aug 27 23:09:18 2001, os: UnixNous allons l'utiliser pour écrire un script nommé smartzip qui peut décompresser automatiquement des fichiers bzip2, gzip et zip :
#!/bin/sh ftype=`file "$1"` case "$ftype" in "$1: Zip archive"*) unzip "$1" ;; "$1: gzip compressed"*) gunzip "$1" ;; "$1: bzip2 compressed"*) bunzip2 "$1" ;; *) error "Le fichier $1 ne peut pas etre décompressé avec smartzip";; esacVous remarquerez que nous avons utilisé ici une nouvelle variable appelée $1. Cette variable contient le premier argument donné au programme. Supposons que nous exécutions
select var in ... ; do break done .... maintenant $var peut être utilisé ....Voici un exemple :
#!/bin/sh echo "Quel est votre OS préféré ?" select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do break done echo "Vous avez sélectionné $var"Voici ce que fait ce script :
Quel est votre OS préféré ? 1) Linux 2) Gnu Hurd 3) Free BSD 4) Other #? 1 Vous avez sélectionné LinuxDans le shell, vous disposez des instructions de boucles suivantes :
while ...; do .... doneLa boucle while va être exécutée tant que l'expression testée est vraie. Le mot clé break peut être utilisé pour quitter la boucle n'importe quand. Avec le mot clé continue, la boucle se poursuit à l'itération suivante en ignorant le reste du corps de la boucle.
for var in ....; do .... doneLe code suivant affiche les lettres de A à C à l'écran :
#!/bin/sh for var in A B C ; do echo "var est $var" doneVoici un exemple de script plus utile, appelé showrpm, qui affiche un résumé du contenu de plusieurs paquetages RPM :
#!/bin/sh # liste un résumé du contenu de plusieurs paquetages RPM # USAGE: showrpm rpmfile1 rpmfile2 ... # EXEMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm for rpmpackage in $*; do if [ -r "$rpmpackage" ];then echo "=============== $rpmpackage ===============" rpm -qi -p $rpmpackage else echo "ERREUR: showrpm ne peut pas lire le fichier $rpmpackage" fi doneVous noterez ci-dessus, l'apparition d'une nouvelle variable spéciale, $*, qui contient la liste de tous les arguments de la ligne de commande. Si vous exécutez
#!/bin/sh echo *.jpgCeci affichera "mail.jpg tux.jpg".
#!/bin/sh echo "*.jpg" echo '*.jpg'Ce programme va afficher deux fois "*.jpg".
#!/bin/sh echo $SHELL echo "$SHELL" echo '$SHELL'Ce programme affichera :
/bin/bash /bin/bash $SHELLEnfin il est possible de retirer la signification particulière de n'importe quel caractère en le faisant précéder d'un anti-slash :
echo \*.jpg echo \$SHELLQui affichera :
*.jpg $SHELLLes "Here documents"
#!/bin/sh # Si nous avons moins de 3 arguments, on affiche le message d'aide if [ $# -lt 3 ] ; then cat <<HELP ren -- renomme plusieurs fichiers en utilisant des expressions regulières de sed USAGE: ren 'regexp' 'replacement' files... EXEMPLE: renomme tous les fichiers *.HTM en *.html: ren 'HTM$' 'html' *.HTM HELP exit 0 fi OLD="$1" NEW="$2" # la command shift retire un argument de la liste des arguments de # la ligne de commande shift shift # la variable $* contient maintenant tous les fichiers. for file in $*; do if [ -f "$file" ] ; then newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` if [ -f "$newfile" ]; then echo "ERREUR: $newfile existe deja" else echo "fichier $file renommé en $newfile ..." mv "$file" "$newfile" fi fi doneCe script est le plus complexe écrit jusqu'ici. Étudions-le plus en détail. La première instruction if teste si nous avons bien fourni au programme un minimum de trois arguments de ligne de commande (la variable spéciale $# contient le nombre d'arguments). Si ce n'est pas le cas, le texte d'aide est envoyé à la commande cat, qui, à son tour, l'affiche sur l'écran. Une fois cette aide affichée, nous sortons du programme. Si trois arguments ou plus, sont présents, le premier est affecté à la variable OLD et le second à la variable NEW. Nous éliminons ensuite ces deux arguments de la ligne de commande, par la commande shift, pour placer le troisième argument en première position dans $*. Avec $* nous entrons dans la boucle. Les arguments dans $* sont affectés un par un à la variable $file. Nous vérifions d'abord que le fichier existe puis nous construisons un nouveau nom de fichier en utilisant le "chercher-remplacer" de sed. Les "backticks" sont utilisés pour affecter le résultat à la variable newfile. Nous avons maintenant tout le néssaire : l'ancien nom de fichier et le nouveau. Ceux-ci vont être utilisés par la commande mv pour renommer le fichier.
nom_de_la_fonction() { # dans le corps de la fonction, $1 est le 1er argument passé à celle-ci # $2 le second ... corps de la fonction }Une fonction doit être déclarée au début du script, avant toute utilisation.
#!/bin/sh # vim: set sw=4 ts=4 et: help() { cat <<HELP xtitlebar -- change le nom d'un xterm, gnome-terminal ou d'une konsole kde USAGE: xtitlebar [-h] "string_for_titelbar" OPTIONS: -h help texte EXEMPLE: xtitlebar "cvs" HELP exit 0 } # en cas d'erreur ou si l'option -h est passée en argument, nous appelons la # fonction help : [ -z "$1" ] && help [ "$1" = "-h" ] && help # envoie la sequence d'échappement pour changer la barre de titre du xterm : echo -e "\033]0;$1\007" #Une bonne habitude à prendre est de toujours avoir une aide la plus complète possible dans les scripts. Ceci permet à d'autres personnes (vous compris) de comprendre et d'utiliser le script.
#!/bin/sh help() { cat <<HELP ceci est un exemple d'analyseur générique de ligne de commande USAGE EXEMPLE: cmdparser -l hello -f -- -somefile1 somefile2 HELP exit 0 } while [ -n "$1" ]; do case $1 in -h) help;shift 1;; # appel de la fonction help -f) opt_f=1;shift 1;; # la variable opt_f est définie -l) opt_l=$2;shift 2;; # -l prend un argument -> décalé de 2 --) shift;break;; # fin des options -*) echo "erreur: il n'existe pas d'option $1. -h pour l'aide";exit 1;; *) break;; esac done echo "opt_f est $opt_f" echo "opt_l est $opt_l" echo "premier arg est $1" echo "2nd arg est $2"Essayez-le ! Vous pouvez l'exécuter comme suit :
cmdparser -l hello -f -- -somefile1 somefile2Vous obtenez :
opt_f est 1 opt_l est hello premier arg est -somefile1 2nd arg est somefile2Comment ça marche ? Le script boucle sur la liste de tous les arguments et les compare aux conditions de test de l'instruction case. S'il trouve un argument qui correspond, il positionne alors la variable et décale la ligne de commande d'une position. La convention Unix veut que les options (ce qui commence par un signe moins) soient placées en premier. Vous pouvez indiquer la fin d'une option en inscrivant deux signes moins (--). grep le réclame, par exemple, pour rechercher une chaîne de caractères commençant par un signe moins :
Recherche de -xx- dans le fichier f.txt: grep -- -xx- f.txtNotre analyseur d'option peut également gérer l'option -- comme vous pouvez le voir dans la liste ci-dessus.
cp framework.sh myscriptet inclure les nouvelles fonctionnalités dans "myscript".
#!/bin/sh # vim: set sw=4 ts=4 et: help() { cat <<HELP b2h -- convertit un binaire en décimal. USAGE: b2h [-h] nombre_binaire OPTIONS: -h message d'aide EXAMPLE: b2h 111010 will return 58 HELP exit 0 } error() { # affiche une erreur et quitte le programme echo "$1" exit 1 } lastchar() { # retourne le dernier caractère d'une chaîne dans $rval if [ -z "$1" ]; then # chaîne vide rval="" return fi # wc place des espaces derrière la sortie, c'est pourquoi nous utilisons sed numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` # nous coupons le dernier caractère rval=`echo -n "$1" | cut -b $numofchar` } chop() { # retire le dernier caractère de la chaîne qui est renvoyé dans $rval if [ -z "$1" ]; then # empty string rval="" return fi # wc place des espaces derrière la sortie, c'est pourquoi nous utilisons sed numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` if [ "$numofchar" = "1" ]; then # un seul caractère dans la chaîne rval="" return fi numofcharminus1=`expr $numofchar "-" 1` # conserve tout, sauf le dernier caractère rval=`echo -n "$1" | cut -b 0-${numofcharminus1}` } while [ -n "$1" ]; do case $1 in -h) help;shift 1;; # appel de la fonction help --) shift;break;; # fin des options -*) error "error: pas d'option $1. -h pour l'aide";; *) break;; esac done # Programme principal sum=0 weight=1 # un arg doit être fourni [ -z "$1" ] && help binnum="$1" binnumorig="$1" while [ -n "$binnum" ]; do lastchar "$binnum" if [ "$rval" = "1" ]; then sum=`expr "$weight" "+" "$sum"` fi #retire la dernière position dans $binnum chop "$binnum" binnum="$rval" weight=`expr "$weight" "*" 2` done echo "le binaire $binnumorig est le décimal $sum" #L'algorithme, utilisé dans ce script, prend le poids décimal de chaque chiffre (1, 2, 4, 8, 16...), en partant du chiffre le plus à droite, et l'ajoute à la somme si le chiffre est un 1. Ainsi, "10" se décompose comme suit :
#!/bin/sh # vim: set sw=4 ts=4 et: ver="0.1" help() { cat <<HELP rotatefile -- effectue une rotation de nom de fichier USAGE: rotatefile [-h] nom_fichier OPTIONS: -h affiche l'aide EXEMPLE: rotatefile out Ceci va, par exemple, renommer out.2 en out.3, out.1 en out.2, out en out.1 et créer un fichier vide out. Le nombre maximum de fichier est 10 version $ver HELP exit 0 } error() { echo "$1" exit 1 } while [ -n "$1" ]; do case $1 in -h) help;shift 1;; --) break;; -*) echo "erreur: pas d'option $1. -h pour l'aide";exit 1;; *) break;; esac done # input check: if [ -z "$1" ] ; then error "ERREUR: vous devez spécifier un fichier, utilisez -h pour l'aide" fi filen="$1" # rename any .1 , .2 etc file: for n in 9 8 7 6 5 4 3 2 1; do if [ -f "$filen.$n" ]; then p=`expr $n + 1` echo "mv $filen.$n $filen.$p" mv $filen.$n $filen.$p fi done # renomme le fichier original : if [ -f "$filen" ]; then echo "mv $filen $filen.1" mv $filen $filen.1 fi echo touch $filen touch $filenComment fonctionne le programme ? Après avoir vérifié que l'utilisateur a fourni un nom de fichier, le programme entre dans une boucle décrémentale de 9 à 1. Le fichier 9, est alors renommé 10, le fichier 8 est renommé 9, et ainsi de suite. A la sortie de la boucle nous renommons le fichier original en 1 et nous créons un fichier vide avec le nom du fichier original.
sh -x scriptetrangeCette commande lancera le script en affichant toutes les instructions exécutées ainsi que les valeurs des variables et des méta-caractères.
sh -n votre_scriptSi vous ne voyez rien sur votre écran, c'est que votre programme ne contient pas d'erreur de syntaxe.
|
Site Web maintenu par l´équipe d´édition LinuxFocus
© Katja and Guido Socher, FDL LinuxFocus.org Cliquez ici pour signaler une erreur ou envoyer un commentaire à Linuxfocus |
Translation information:
|
2001-11-01, generated by lfparser version 2.18