Vous n'êtes pas identifié(e).
L'icône rouge permet de télécharger chaque page du wiki visitée au format PDF et la grise au format ODT →
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente Prochaine révision Les deux révisions suivantes | ||
doc:programmation:shells:debuter-avec-les-scripts-shell-bash [30/05/2014 07:03] Hypathie [enchaînements de commandes dans les scripts: utiliser la distinction code de retour/résultat de commande] |
doc:programmation:shells:debuter-avec-les-scripts-shell-bash [30/05/2014 07:04] Hypathie [variable et calcul sur les entiers] |
||
---|---|---|---|
Ligne 593: | Ligne 593: | ||
Pour plus de précision sur la création et l'utilisation de tableau dans les scripts voir ici : [[atelier:chantier:page-man-bash-v-les-tableaux]] | Pour plus de précision sur la création et l'utilisation de tableau dans les scripts voir ici : [[atelier:chantier:page-man-bash-v-les-tableaux]] | ||
- | =====Variable et substitution de commandes ===== | ||
- | *$( ) | ||
- | Une commande entourée par $( ) est exécuté puis la chaîne $(commande) peut être affectée à une variable.On peut donc appeler la valeur du retour d'une commande.\\ | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | dir=$(pwd) | ||
- | echo "mon répertoire est : $dir" | ||
- | </code> | ||
- | <code> | ||
- | mon répertoire est : /home/hypathie | ||
- | </code> | ||
- | *plusieurs commandes: | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | echo $(pwd ; ls) | ||
- | </code> | ||
- | On peut aussi imbriquer les commandes ainsi : | ||
- | <code bash> | ||
- | echo $( ls $(pwd)/Documents) | ||
- | </code> | ||
- | *avec set : | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | set $(pwd ; whoami) | ||
- | echo "$1 : $2" | ||
- | echo $# | ||
- | </code> | ||
- | Ou | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | set -- $(ls -l $(pwd)/.bashrc) | ||
- | echo $* | ||
- | </code> | ||
- | On ne confondra pas une paire de parenthèses précédée d'un $ avec une paire de parenthèse autour d'une suite de commandes !\\ | ||
- | Voir chapitre suivant ;-) | ||
- | |||
- | =====Les redirections dans les scripts===== | ||
- | Voir :\\ | ||
- | *[[doc:programmation:bash#script]] : **Ce sont :** | ||
- | <code bash> | ||
- | > >> < << >& | | ||
- | </code> | ||
- | *Prérequis : [[doc:programmation:shell:shell#rediriger-l-affichage]] et le lien qu'on y trouve [[doc:programmation:shell:chevrons]] | ||
- | |||
- | ====Rappels :==== | ||
- | |||
- | Les redirections permettent de travailler non pas en se servant du code de retour (qui indique la réussite ou l'échec de l'exécution d'une commande) mais sur le résultat d'une commande.\\ | ||
- | Un processus unix possède (par défaut) trois voies d'interaction entre le système et l'utilisateur. Une entrée et deux sorties. Chacun de ces "lieux" sont identifiés par un descripteur de fichier. | ||
- | -une entrée standard (par défaut le clavier stdin), de descripteur 0 (nom de l'entrée du processus, ne pas confondre avec le code de retour !); | ||
- | -une sortie standard (par défaut l'écran stdout), de descripteur 1 ; | ||
- | -une sortie standard pour les message d'erreur (stderr) de descripteur 2. | ||
- | |||
- | Pour chaque programme lancé, un flux est créé. Ce flux est une sorte de canal par lequel transite les données entre les espaces, entrée et sortie.\\ | ||
- | On peut imaginer un terminal, comme la réunion virtuelle d'un clavier et d'un écran. | ||
- | **Merci à captnfab pour cette comparaison sur IRC** :-D | ||
- | <code bash> | ||
- | <&- <&- # Permettent la fermeture de l'entrée standard et de la sortie standard. | ||
- | >| # Force une redirection vers un fichier.txt pour pouvoir écraser | ||
- | le fichier quand il existe et que l'option noclobber (-c) est activée. | ||
- | </code> | ||
- | ====1) opérateurs de sortie : ==== | ||
- | <code bash> | ||
- | > : crée un fichier ou le réactualise ; redirige le canal choisi vers un fichier et force sa création, si le fichier existe son contenu est recrée et numéro d'inode du fichier d'origine est conservé. | ||
- | </code> | ||
- | <code bash> | ||
- | ls -l >chemin-fichier.txt | ||
- | </code> | ||
- | est un équivalent de : | ||
- | <code bash> | ||
- | ls -l 1> chemin-fichier.txt | ||
- | </code> | ||
- | ===Dans un script :=== | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | # mise en place : | ||
- | { mkdir ~/ABCD ; cd ABCD ; touch a b c d ; cd ~ ; pwd ;} | ||
- | |||
- | # création de fichier avec " > " : | ||
- | cd ~/ABCD && > fichier1 && pwd ; cd ~ && pwd && > /home/hypathie/ABCD/fichier2 && pwd && cd ~ && pwd | ||
- | # espace facultatif avant et après " > " | ||
- | |||
- | # redirection de la sortie de commande vers un fichier : | ||
- | ls>/home/hypathie/ABCD/recup-ls # espace facultatif avant et après " > " | ||
- | </code> | ||
- | |||
- | Retour : | ||
- | <code bash> | ||
- | /home/hypathie # après cd ~ on est retourné dans le répertoire de l'utilisateur | ||
- | /home/hypathie/ABCD # après création du fichier1 on est encore dans "ABCD" | ||
- | /home/hypathie # après cd ~ on est retourné dans le répertoire utilisateur | ||
- | /home/hypathie # on a créé fichier2 dans "ABCD" depuis le répertoire utilisateur | ||
- | /home/hypathie | ||
- | </code> | ||
- | <note important> | ||
- | Attention: | ||
- | Créer un fichier avec > est un bashisme. La méthode universelle est d'utiliser "touch". | ||
- | Amateurs de magie blanche et noire voir ce fil : [[http://debian-facile.org/viewtopic.php?pid=86634#p86634]] | ||
- | </note> | ||
- | *redirection de commande vers un fichier, si le fichier existe, les données sont ajoutées à la suite du fichier. | ||
- | <code bash> | ||
- | >> | ||
- | </code> | ||
- | |||
- | *La sortie standard d'erreur peut être dirigée vers un fichier en le créant ou en l'écrasant : | ||
- | <code bash> | ||
- | ls vi 2>err # retour du prompt : le message d'erreur a été inscrit | ||
- | dans le fichier "erreurs" qui s'est créé s'il n'existait pas. | ||
- | </code> | ||
- | * On peut aussi concaténer : | ||
- | <code bash> | ||
- | 2>>fichier # si "fichier" n'existait pas le message | ||
- | d'erreur aurait été ajouté en dernière ligne. | ||
- | </code> | ||
- | *Elle peut aussi être dirigée vers le fichier "poubelle" ou "puits" : | ||
- | <code bash> | ||
- | 2>/dev/null | ||
- | </code> | ||
- | (Tout ce qui y est dirigé est perdu, inutile de concaténer !) | ||
- | On s'en sert souvent lorsqu'on est intéressé par le fait de récupérer le code de retour. | ||
- | |||
- | *redirection de la sortie d'une commande vers un autre canal : | ||
- | <code bash> | ||
- | >& | ||
- | </code> | ||
- | <code bash> | ||
- | ls -l 1>&2 la sortie du répertoire courant et envoyé sur le canal de sortie d'erreur ; | ||
- | cela à pour effet, de lister le contenu, mais le terminal affiche alors le canal | ||
- | de sortie d'erreur. Relancer la dernière commande est impossible. | ||
- | On peut lancer une autre commande, ou faire ctrl+c. Oouffff | ||
- | </code> | ||
- | * Pour diriger la sortie standard et la sortie d'erreur à la fin d'un fichier : | ||
- | <code bash> | ||
- | >>& | ||
- | </code> | ||
- | * Pour rediriger la sortie standard des messages d'erreur (stderr) vers la sortie standard #(stdout), on utilise la syntaxe : | ||
- | <code bash> | ||
- | 2>&1 | ||
- | </code> | ||
- | |||
- | Par exemple : | ||
- | |||
- | <code bash> | ||
- | ##vi: /usr/bin/vi | ||
- | ls vi 2>&1 2>erreurs # retour du prompt on retrouve le message d'erreurs | ||
- | dans le fichier "erreurs" qui s'est créé. | ||
- | Cela un équivalent de ls vi 2>err | ||
- | </code> | ||
- | |||
- | <code bash> | ||
- | ls vi erreur>errrrr 2>&1 #retour du prompt | ||
- | ls ne peut lister le fichier vi ; le message d'erreur | ||
- | est envoyé dans le fichier "errrr" qui est nouvellement créé | ||
- | et qui est la sortie standard (1), | ||
- | puis ls ne peut lister le fichier "erreur", le message est | ||
- | envoyé vers la sortie d'erreur qui est redirigé vers (1) | ||
- | c'est-à-dire le fichier "erreur". | ||
- | </code> | ||
- | ====2)Opérateurs d'entrée : ==== | ||
- | <code bash> | ||
- | < Place, en entrée d'une commande, un contenu. | ||
- | </code> | ||
- | <code bash> | ||
- | cat < /chemin/du/fichier.txt # est un équivalent de cat /chemin/du/fichier.txt | ||
- | </code> | ||
- | <code bash> | ||
- | << Redirige en entrée une série de données. | ||
- | </code> | ||
- | On nomme cette redirection "label". Redirection utilisée dans un document en ligne dont on se sert que pour certaines commandes, comme ftp ou cat.\\ Voir : [[http://abs.traduc.org/abs-5.0-fr/ch18.html#heredocref]]\\ | ||
- | Ne pas confondre avec la commande e2label, voir : [[doc:systeme:e2label]] | ||
- | |||
- | ====3) Un petit exercice sur opérateurs d'entrée et de sorties ==== | ||
- | Écrire un script qui crée le dossier "ABCD" et 4 fichiers vides (nommés a b c d) ; | ||
- | qui liste le contenu de "ABCD" et qui inscrit le résultat dans un fichier nommé "ls1" qui sera placé dans "ABCD" ; | ||
- | qui depuis le répertoire personnel crée le fichier vide nommé "fichier.txt", liste à nouveau ABCD, inscrit le résultat dans le fichier "ls2", rangé dans "ABCD"; | ||
- | qui permet d'inscrire depuis le terminal une ligne de texte dans le fichier nommé "fichier.txt" ; | ||
- | puis une deuxième ligne de texte dans "fichier.txt", en affichant dans le terminal, le nombre de lignes, de mots et d'octets que possède le fichier "fichier.txt" ; | ||
- | qui se sert de différentes méthodes tout au long du script pour vérifier au niveau du terminal que chaque commande s'est bien déroulée. | ||
- | |||
- | |||
- | Bonne lecture ;-) | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | set -o posix | ||
- | { mkdir ~/ABCD 2>>/dev/null ; echo $? ; cd ABCD && touch a b c d ; echo $? ; ls -l >> ~/ABCD/ls1 ; echo $? ; cd ~ ; pwd ; touch ~/ABCD/fichier.txt ; echo $? ; pwd && ls -l ~/ABCD >> ~/ABCD/ls2 ; echo $? ; read phrase1 && echo ${phrase1} >> ~/ABCD/fichier.txt && echo $? ; read phrase2 ; cat >> ~/ABCD/fichier.txt << EOF | ||
- | $phrase2 | ||
- | EOF | ||
- | echo $? | ||
- | cat < ~/ABCD/fichier.txt | wc | ||
- | echo $? ;} | ||
- | </code> | ||
- | Retour : | ||
- | <code> | ||
- | 0 | ||
- | 0 | ||
- | 0 | ||
- | /home/hypathie | ||
- | 0 | ||
- | /home/hypathie | ||
- | 0 | ||
- | J'écris un script, | ||
- | 0 | ||
- | avec les opérateurs de redirection. | ||
- | 0 | ||
- | 2 8 57 | ||
- | 0 | ||
- | </code> | ||
- | |||
- | * **2>>/dev/null** : permet ici de relancer le script autant de fois qu'on veut, sans voir apparaître de message d'erreur : mkdir fichier-existant ne réinitialise pas un fichier de type dossier en le vidant. | ||
- | * **$?** : permet ici de vérifier que la commande précédente s'est déroulée avec succès quand "**;**" a été utilisé, inutile de vérifier avec **&&**. | ||
- | |||
- | |||
- | ====4) Tube, Redirection, Code de retour, Paramètres de position==== | ||
- | |||
- | ===un script de synthèse sur toutes ces notions=== | ||
- | |||
- | * **Pré-requis : [[atelier:chantier:debuter-avec-les-scripts-shell-bash#la-commande-interne-shift|la commande shift]]** | ||
- | * **Rappel rapide des syntaxes de grep :** | ||
- | |||
- | **grep [option(s)] "regex" /chemin/fichier/avec/texte**\\ | ||
- | ou\\ | ||
- | **commande-avec-sortie-texte | grep [option(s)] "motif"**\\ | ||
- | (on cherche la chaîne "motif" en filtrant la sortie d'une commande)\\ | ||
- | |||
- | grep -E : regex étendue\\ | ||
- | |||
- | **Sur GREP tout est là : [[doc:systeme:grep]]** | ||
- | |||
- | * **Sur les expressions régulières voir : [[atelier:chantier:bash-vii-globs-etendus-regex?&#liste-des-caracteres-utilises-dans-les-expressions-regulieres-etendues]]** | ||
- | |||
- | **Voici un petit script "exp.reg1" qui regroupe les notions étudiées jusqu'à présent.**\\ | ||
- | Il a pour but de s'exercer aux expressions régulières.\\ | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | #Les "echo" les plus à droite sont là pour expliquer lors du retour ce qui s'y passe dans ce script. | ||
- | |||
- | VAR="$1" | ||
- | echo "La valeur de VAR est: $VAR." | ||
- | echo "Il y a "$#" paramètres." | ||
- | echo "Le paramètre n°1 est "$1" (la 'ER')." | ||
- | echo "Le paramètre n°2 est "$2" (deuxième argument, chaine1 à matcher)." | ||
- | echo "Le paramètre n°2 est "$3" (le troisième argument, chaine2 à matcher." | ||
- | echo " " | ||
- | shift | ||
- | echo "Avec 'shift', on se décale d'un paramètre." | ||
- | echo "Après 'shift', il reste donc: "$#" paramètre(s)." | ||
- | echo "Et ce(s) paramètre(s) sont: "$1", "$2"." | ||
- | echo "("$1": ancien deuxième paramètre devenu paramètre 1 après shift)." | ||
- | echo "("$2": ancien troisième paramètre devenu paramètre 2 après shift.)" | ||
- | echo " " | ||
- | echo "MAIS LA VALEUR DE VAR RESTE la 'ER' : "$VAR"." | ||
- | for i in "$@" | ||
- | do | ||
- | echo " " | ||
- | echo "'for i in \$@': la variable i aura, boucle après boucle, les VALEURS: "$@"," | ||
- | echo "(attribués à chaque tour de boucle à variable "i".)" | ||
- | echo "c'est-à-dire lors de la boucle n°1, elle est identique au paramètre n°1: "$1"." | ||
- | echo "puis lors de la boule n°2, elle est identique au paramètre n°2 : "$2"." | ||
- | echo " " | ||
- | echo "On peut donc donner à grep la chaine:$i comme entrée par le tube," | ||
- | echo "et comme motif le 'ER': $VAR." | ||
- | echo "$i" | grep -E "$VAR" > /dev/null | ||
- | if [ $? -eq 0 ] | ||
- | then | ||
- | echo " " | ||
- | echo " BRAVO ! La ER: $VAR correspond au motif "$i" " | ||
- | else | ||
- | echo " " | ||
- | echo " ERREUR ! La ER: $VAR ne correspond pas au motif: $i " | ||
- | echo " " | ||
- | fi | ||
- | done | ||
- | |||
- | # ligne 33 (if) : $? (code de retour) -eq (égal à) zéro (pas d'erreur de sortie, donc bonne correspondance) | ||
- | </code> | ||
- | |||
- | **Lancez-le ainsi (explications détaillées dans le retour) :**\\ | ||
- | (en considérant que le dossier parent de ce script figure dans $PATH, après modification du fichier ~/.bashrc\\ | ||
- | voir : [[atelier:chantier:debuter-avec-les-scripts-shell-bash#executer-son-script-depuis-n-importe-ou|3) Exécuter son script depuis n'importe où !]]) | ||
- | <code user> | ||
- | exp.reg1 "^[a-b]" "abc" "ABC" | ||
- | </code> | ||
- | |||
- | Retour : | ||
- | |||
- | <code> | ||
- | La valeur de VAR est: ^[a-b]. | ||
- | Il y a 3 paramètres. | ||
- | Le paramètre n°1 est ^[a-b] (la 'ER'). | ||
- | Le paramètre n°2 est abc (deuxième argument, chaine1 à matcher). | ||
- | Le paramètre n°2 est ABC (le troisième argument, chaine2 à matcher. | ||
- | |||
- | Avec 'shift', on se décale d'un paramètre. | ||
- | Après 'shift', il reste donc: 2 paramètre(s). | ||
- | Et ce(s) paramètre(s) sont: abc, ABC. | ||
- | (abc: ancien deuxième paramètre devenu paramètre 1 après shift). | ||
- | (ABC: ancien troisième paramètre devenu paramètre 2 après shift.) | ||
- | |||
- | MAIS LA VALEUR DE VAR RESTE la 'ER' : ^[a-b]. | ||
- | |||
- | 'for i in $@': la variable i aura, boucle après boucle, les VALEURS: abc ABC, | ||
- | (attribués à chaque tour de boucle à variable i). | ||
- | c'est-à-dire lors de la boucle n°1, elle est identique au paramètre n°1: abc. | ||
- | puis lors de la boule n°2, elle est identique au paramètre n°2 : ABC. | ||
- | |||
- | On peut donc donner à grep la chaine:abc comme entrée par le tube, | ||
- | et comme motif le 'ER': ^[a-b]. | ||
- | |||
- | BRAVO ! La ER: ^[a-b] correspond au motif abc | ||
- | |||
- | 'for i in $@': la variable i aura, boucle après boucle, les VALEURS: abc ABC, | ||
- | (attribués à chaque tour de boucle à variable i). | ||
- | c'est-à-dire lors de la boucle n°1, elle est identique au paramètre n°1: abc. | ||
- | puis lors de la boule n°2, elle est identique au paramètre n°2 : ABC. | ||
- | |||
- | On peut donc donner à grep la chaine:ABC comme entrée par le tube, | ||
- | et comme motif le 'ER': ^[a-b]. | ||
- | |||
- | ERREUR ! La ER: ^[a-b] ne correspond pas au motif: ABC | ||
- | </code> | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | =====variable et calcul sur les entiers===== | ||
- | Nous allons voir différentes méthodes pour faire de calcul | ||
- | |||
- | ==== 1) valeur numérique avec déclare -i==== | ||
- | |||
- | <note important> | ||
- | Méthode non POSIX | ||
- | </note> | ||
- | |||
- | La valeur d'une variable peut une expression arithmétique, pour initialiser une variable de type entier on utilise l'option -i de la commande declare : declare -i nom[=expression] nom[=expression] ... | ||
- | |||
- | <code bash> | ||
- | #!/bin/bash | ||
- | declare -i x=35*2 | ||
- | echo $x | ||
- | </code> | ||
- | retour | ||
- | <code> | ||
- | 70 | ||
- | </code> | ||
- | |||
- | Pour que la valeur d'une variable ne soit pas accidentellement modifier, il faut ajouter l'attribut -r. | ||
- | |||
- | <code bash> | ||
- | #!/bin/bash | ||
- | declare -ir a=35*2 | ||
- | declare -ir b=5+5 | ||
- | echo $(($a+$b)) | ||
- | </code> | ||
- | retour | ||
- | <code> | ||
- | 80 | ||
- | </code> | ||
- | |||
- | ====2) valeur numérique avec let==== | ||
- | Cette commande permet elle aussi d'effectuer des calculs avec les variables. | ||
- | |||
- | <code bash> | ||
- | #!/bin/bash | ||
- | let "a = 10" | ||
- | let "b = 2" | ||
- | let "c = a+b" | ||
- | echo $c | ||
- | let "e = 10*2" | ||
- | echo $e | ||
- | let "f = 15" | ||
- | let "f *=2" | ||
- | echo $f | ||
- | </code> | ||
- | Retour | ||
- | <code> | ||
- | 12 | ||
- | 20 | ||
- | 30 | ||
- | </code> | ||
- | |||
- | ====3)convertir les nombre d'une base à l'autre==== | ||
- | À savoir : utiliser la commande bc | ||
- | *convertir de décimal au binaire : obase | ||
- | <code user> | ||
- | echo 'obase=2;50' | bc | ||
- | </code> | ||
- | =>110010 | ||
- | *convertir du binaire au décimal : ibase | ||
- | <code user> | ||
- | echo 'ibase=2;100110111101' | bc | ||
- | </code> | ||
- | =>2493 | ||
- | |||
- | *convertir de l'hexadécimal (2F) au binaire : ibase;obase | ||
- | <code user> | ||
- | echo 'ibase=16;obase=2;2F' | bc | ||
- | </code> | ||
- | =>101111 | ||
- | |||
- | |||
- | ====4) considérations avancées==== | ||
- | |||
- | Pré-requis : [[atelier:chantier:page-man-bash-iv-symboles-dans-les-calculs-mathematiques]] | ||
- | |||
- | Même lien pour la commande interne : | ||
- | <code> | ||
- | ((expression-arithmitique)) | ||
- | </code> | ||
- | |||
- | Avec cette commande interne,\\ | ||
- | outre les opérateurs arithmétiques de calculs basiques (+ - * / %)\\ | ||
- | bash intègre les opérateurs arithmétiques de décalages binaires à droite et à gauche : | ||
- | <code> | ||
- | >> et << | ||
- | </code> | ||
- | |||
- | et les opérateurs d'opérations binaires : | ||
- | * & : et | ||
- | * | : ou | ||
- | * ^ : ou exclusif | ||
- | * ~ : négation binaire | ||
- | |||
- | Les blancs (espace), ne sont pas obligatoires, mais ils améliorent la lisibilité du code !\\ | ||
- | |||
- | ===notion de constante numérique=== | ||
- | La constante numérique par défaut est de base 10 : ouffffff ;-) | ||
- | |||
- | Mais on peut la modifier, pour manipuler les données binaires ou octales !\\ | ||
- | |||
- | **La syntaxe est la suivante : nombre** | ||
- | * si "nombre" commence par 0, la constante est considérée comme octale (base 8); | ||
- | * si "nombre" commence par 0x, elle est considérée comme hexadécimale (base 16) | ||
- | |||
- | **Autre syntaxe: base#nombre** | ||
- | *où l'on remplace "base" par la base souhaitée, et le nombre est la valeur numérique à traiter. | ||
- | |||
- | Exemple de manipulation logique sur les décimaux : | ||
- | |||
- | <code bash> | ||
- | #!/bin/bash | ||
- | var1=10#10 #base 10 | ||
- | var2=10#5 | ||
- | |||
- | echo $(($var1 & $var2)) #10 et 5 | ||
- | echo $(($var1 | $var2)) #10 ou 5 = aucun =0 | ||
- | echo $(($var1 ^ $var2)) # | ||
- | #echo $(($var1 <<2)) | ||
- | echo $(($var1 >>2)) | ||
- | </code> | ||
- | Retour | ||
- | <code> | ||
- | 0 | ||
- | 15 | ||
- | 15 | ||
- | 2 | ||
- | </code> | ||
- | Exemple de manipulation logique sur les binaires : | ||
- | |||
- | <code> | ||
- | #!/bin/bash | ||
- | var1=2#00010110 #base 2 | ||
- | var2=2#0011001 | ||
- | |||
- | echo $(($var1 & $var2)) | ||
- | echo $(($var1 | $var2)) | ||
- | echo $(($var1 ^ $var2)) | ||
- | #echo $(($var1 <<2)) #88 | ||
- | echo $(($var1 >>2)) | ||
- | </code> | ||
- | Retour | ||
- | <code> | ||
- | 16 | ||
- | 31 | ||
- | 15 | ||
- | 5 | ||
- | </code> | ||