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 →
Ceci est une ancienne révision du document !
- Pour choisir, voir les autres Tags possibles dans l'Atelier.
Nota :
Contributeurs, les sont là pour vous aider, supprimez-les une fois le problème corrigé ou le champ rempli !
Ré-requis indispensables :
Vous savez donc ce qu'est le shell, un alias et un script.
Mais quel rapport entre la diversité des shell (ou interpréteur de commandes) qui existent (sh ; bsh ; bash ; ksh, etc.) et les scripts ?
C'est que dans l'en-tête du script l'un de ces shell doit être appelé avec le sha-bang:
#!/bin/sh #!/bin/bash #!/bin/perl #!/bin/tcl
Chacune de ces lignes appelle un interpréteur de commandes différent.
POSIX est un standard2).
Appeler bash avec l'option –posix ou insérer set -o posix au début du script fait que bash se conforme au standard posix.
À savoir :
Pour utiliser tcsh, ksh, ash, sh, csh, etc :
http://formation-debian.via.ecp.fr/shell.html
méthode d'installation de ksh
Apprendre le BASH sans devenir un ultra-bashiste“ : si si c'est possible !
En général, tous les shell acceptent la même syntaxe de base telle que définie par POSIX, mais chacun accepte une syntaxe étendue qui lui est propre (et donc incompatible avec les autres shells).
Voici quelques aspects auxquels se référer à chaque fois que vous apprendrez une nouvelle notion relative au shell BASH.
POSIX | À éviter : bashisme |
---|---|
if [ “$toto” = “$titi” ] ; then … | if [ “$toto” == “$titi” ] ; then … |
diff -u fichier.c.orig fichier.c d | diff -u fichier.c{.orig,} |
mkdir /tototiti /tototutu | mkdir /toto{titi,tutu} |
funcname() { … } | function funcname() { … } |
format octal : « \377 » | format hexadécimal : « \xff » |
Pour plus de détails sur chacun de ces points voir : Guide avancé d'écriture des scripts Bash :36.9. Problèmes de portabilité
Il s'agit là plutôt d'un aboutissement, essayons d'acquérir par des exemples très simples, les connaissances de bases qui permettront de comprendre chacun de ces points, ainsi que ce que l'on trouve ici : scripts
Il y a différentes méthodes pour lancer ses scripts, cela dépend, vous l'aurez compris, du répertoire dans lequel sont placés ses scripts.
touch mon-script
Si l'on a exécuté cette commande à l'ouverture de son terminal, le fichier “mon-script” est alors placé dans son répertoire courant.
Et oui une script est un simple fichier texte dont le contenu (une suite de commandes et d'instruction) est exécutable.
À savoir :
chmod u+x mon-script
Voyons maintenant trois méthodes pour exécuter un script
nano mon-script
dans lequel on inscrit :
echo -n "Bonjour les copains"
ATTENTION il faut penser à se déplacer dans le répertoire parent de ce script avant de lancer l'exécution.
bash mon-script
Bonjour les copainsutiliateur@debian:~$
/bin/echo -n "Bonjour les copains"
La commande echo est une commande interne du shell ; la commande /bin/echo est une commande à part.
merci captnfab
Essayez maintenant :
bash --posix mon-script
Bonjour les copainsutilisateur@debian:~$
#!/bin/bash ls /home/utilisateur
./mon-script
À voir : modifier-durablement-la-valeur-de-la-variable-d-environnement-path
Il faut pour cela placer le chemin absolu de son script dans le PATH, c'est-à-dire dans l'un des répertoires /bin, /usr/bin ou /usr/local/bin
Les scripts que l'on crée sont ceux de l'utilisateur, on peut donc ajouter le chemin du répertoire dans lequel on range ses scripts
-en éditant le fichier ~/.bashrc qui est un fichier caché du répertoire courant de l'utilisateur (son HOME);
-et en y ajoutant à la fin la ligne PATH=$PATH”:$HOME/MesScripts“
mkdir MesScripts
nano ~/.bashrc
PATH=$PATH":$HOME/MesScripts"
nano mon-script
##!/bin/bash echo "Coucou tout le monde !"
chmod u+x ~/mon-script
mv ~/mon-script ~/MesScripts/
(Voir exemple ci-dessous : “Un petit script pour lancer un script depuis n'importe où !”)
mon-script
Coucou tout le monde !
echo $PATH #retour: /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/utilisateur/MesScripts
Pas si difficile que ça
Voyons pour finir la méthode qui vérifie la compatibilité de son script avec la norme POSIX :
nano ~/MesScripts/mon-script
#!/bin/bash set -o posix echo -n "Bonjour $USER"
Le prompt vous dira “bonjour” avec l'option -n !
Pas d'inquiétude si vous ne comprenez pas tout ; vous en en serez capable après avoir suivi ce wiki et consulté ses liens. Il faut :
#!/bin/bash set -o posix printf "Un nouveau script $USER ? Son nom : " { read nom ; echo "#!/bin/bash" >> $nom ; chmod u+x $nom ; mv ~/$nom ~/MesScripts ; /usr/bin/gedit ~/MesScripts/$nom ;}
scriptx
Retour :
Un nouveau script toto ? Son nom :
Lors de l'exécution de ce script, la chaîne que vous entrerez pour répondre à la question, sera le nom d'un nouveau script que vous voulez créer.
En liens nécessaires :
Le shell pour tous : "Variables et environnement"
variables
Le nom d'une variable est un simple pointeur vers l'emplacement mémoire où sont conservées les données qu'elle contient.
Les variables qu'on crée dans un script (ou dans le terminal) sont localisées dans ce script (ou à l'ouverture d'un terminal) c'est-à-dire qu'elles ne sont utilisables que lorsqu'on exécute son script, (ou que l'on appelle la valeur d'une variable qu'on vient de déclarer dans un terminal). Et il s'agit du script d'un utilisateur, il faut les distinguer des variables de substitution prédéfinies et des variables d'environnement prédéfinies.
Mais comment enregistrer une valeur en mémoire ?
Comme vous allez le comprendre, une valeur est mémorisée au moyen de l'un des mécanismes internes du shell et il y en a plusieurs.
C'est par exemple, l'affectation d'une valeur au nom d'une variable qui va permettre d'enregistrer en mémoire cette variable avec sa valeur
Voyons d'abord comment créer une variable de cette manière et comment utiliser sa valeur.
Avant tout prenez bien conscience que la déclaration d'une variable n'est pas confinée au script, mais qu'il est possible de déclarer une variable dans le shell courant (dans le terminal). Voir absolument : détail sur le caractère $.
#!/bin/bash NomDelaVariable=ValeurDeLaVariable
⇒ La valeur “ValeurDeLaVariable” a été mémorisée.
#!/bin/bash nx_fichier=les-fonctions touch ~/$nx_fichier ls -la ~/$nx_fichier
⇒ Les programmes (ou commandes) “touch” et “ls” ont utilisé la valeur de la fonction nommée “nx_fichier”, d'une valeur qui correspond à la chaîne de caractères “les_fonctions”.
#!/bin/bash var1=a var2=texte var3="texte avec espaces" var4=55 var5=$var1 #ici on affecte à la variable var5, la valeur de la variable var1 var6=$0 #ici on affecte à la variable var6, la valeur de la variable pré-définie $0 (1) echo -e "valeur de var1: $var1\nvaleur de var2: $var2\nvaleur de var3: $var3\nvaleur de var3: $var4\nvaleur de var5: $var5\nvar6: $var6"
(1) $0 a pour valeur pré-définie le nom du programme
Retour :
valeur de var1: a valeur de var2: texte valeur de var3: texte avec espaces valeur de var3: 55 valeur de var5: a var6: /home/hypathie/MesScripts/mon-script
#!/bin/bash set -o posix var1=a var2=texte var3="texte avec espaces" var4=55 var5=$var1 var6=$0 /bin/echo -e "valeur de var1: $var1\nvaleur de var2: $var2\nvaleur de var3: $var3\nvaleur de var3: $var4\nvaleur de var5: $var5\nvar6: $var6" # même retour que précédemment
On peut créer des variables au moyen de commandes, comme par exemple la commande read qui est une commande interne (ou primitive) au shell.
read nom-de-la-variable
Par exemple dans un script :
#!/bin/bash echo "Bonjour : qui êtes-vous ?" read nom echo "Enchanté $nom !"
De même dans le terminal on peut tout à fait entrer tour à tour chacune des lignes de ce script, essayez !
#!/bin/bash read -p "entrez votre prénom: " prenom echo "bonjour $prenom !"
Ici “prenom” est le nom de la variable, et sa valeur est entrée par l'utilisateur depuis le terminal. Là aussi ces deux commandes peuvent être entrées dans le terminal.
read -p "entrez votre nom et prénom: " nom prenom
retour:
entrez votre nom et prénom:
On entre par exemple debian facile, puis on peut récupérer la valeur de chacune des variables “nom” et “prenom”
echo $prenom $nom
retour :
facile debian
Mais dans un script c'est plus rapide !
Ci-dessous, on ne met pas le “nom” de la variable, parce qu'on ne cherche pas à appeler la valeur de cette variable mais à permettre au programme de se poursuivre.
Quand on entre dans le terminal la réponse attendu par “read”, le retour de la commande et zéro, donc elle est considérée comme exécutée, et le shell passe à l'exécution de la commande suivante.
#!/bin/bash read -p "entrez votre nom d'utilisateur: " echo "bonjour $USER !"
par exemple:
read -p "entrez votre de naissance (deux derniers chiffres): " -n 2 annee
Les variables de chaque case d'un tableau, ont elles aussi une position définie par l'utilisateur, ou automatiquement lors de la création du tableau.
Pour plus de précision sur la création et l'utilisation de tableau dans les scripts voir ici : page-man-bash-v-les-tableaux
Ne pas confondre le signe = de l'affectation d'une variable par une valeur (voir ci-dessus affectation directe) et l'opérateur de correspondance = (ou == ) utilisé dans les tests.
Dans les tests sur les entiers l'égalité est représentée par l'option -eq !
VoirFonctionnalités avancées du Shell en particulier : structure conditionnelle if pour ce qui suit
#!/bin/bash var1=23 var2=36 if [ $var1 -eq $var2 ] ; then echo "$var1 et $var2 sont égales" else echo "$var1 et $var2 ne sont pas égales" fi if [ $var1 != $var2 ] ; then echo "$var1 et $var2 sont inégales" fi if [ ${#var1} = ${#var2} ] ; then echo "$var1 et $var2 sont des chaînes de même longueur" fi echo "les longueurs sont de : ${#var1} et de : ${#var2}"
De même que la composition de commandes vu plus haut, on se sert de la composition avec les tests. Et oui les doubles crochets et la commande test sont des commandes !
#!/bin/bash #var3 est nulle, non déclarée, (ou non initialisée) : sa valeur est nulle #var2 est initialisée mais sans valeur : sa une valeur vide var1=ma_variable var2= var2bis=" " [ ${var1} ] && echo "$var1" # => ma_variable [ -n ${var1} ] && echo "$var1" # => ma_variable [ -n $var1 ] && echo "$var1" # => ma_variable #ou encore : test $var1 && echo "ok" # => ok test -n $var1 && echo "ok var1 contient quelque-chose" # => ok var1 contient quelque-chose test -z $var1 || echo "NON: var1 ne contient pas rien" # => NON: var1 ne contient pas rien echo " " [ -z $var2 ] && echo "var2: ${#var2} a une valeur vide : ne contient rien" # => var2: 0 a une valeur vide : ne contient rien [ -n $var2 ] && echo "var2: une valeur vide contient 0 : du vide !" # => var2: une valeur vide contient 0 : du vide ! [ -z $var2bis ] && echo "var2bis: comme var2" # => var2bis: comme var2 [ -n $var2bis ] && echo "var2bis: comme var2" # => var2bis: comme var2 echo " " [ -n $var3 ] && echo "ET avec -n: une variable nulle contient aussi du vide" # => ET avec -n: une variable nulle contient aussi du vide [ -n $var3 ] || echo "OU avec -n" # PAS DE RETOUR puisque la première commande a renvoyé le code de retour 0. [ -z $var3 ] && echo " OU avec -z une variable nulle contient aussi du vide" # => OU avec -z une variable nulle contient aussi du vide [ -z $var3 ] || echo " OU avec -z" # PAS DE RETOUR puisque la première commande a renvoyé le code de retour 0.
Attention case n'utilise pas d'expression régulière mais du “pattern matching”
* syntaxe de case :
<code bash>
case $variable in
expression)
instructions
;;
…
esac
</code>
* explications :
- case “teste” la valeur du paramètre passé au script avec chaque “expression” ;
- et en fonction du test il y a exécution ou pas des commandes placées au niveau de “instructions” ;
- Case sert à conditionner l'exécution des commandes en fonction d'argument choisi ;
- On se sert de “l'étoile” pour permettre que soit exécuter quelque chose quand n'importe quel autre paramètre que ceux des expressions, est passé au script;
* Ne pas oublier :
- le double point virgule qui permet de clôturer chaque test ;
- esac pour finir.
* exemple :
<code bash>
#!/bin/bash
# passer le paramètre 'coco' à ce script ; puis 'cucu' ; titi puis toto, puis celui que voulez.
case $1 in
coco)
echo “Vous avez passé le paramètre 'coco', ré-essayez avec 'cucu'”
;;
cucu)
echo “Vous avez passé le paramètre 'cucu'”
echo “un peu d'humour !”
echo “Ré-essayé un paramètre de votre choix.”
;;
titi|toto)
echo “vous avez passé le paramètre $1”
;;
*)
echo “Vous avez choisi $1”
esac
</code>
Vous avez tout en mains pour comprendre ceci : Fonctionnalités avancées du Shell: selecteur-case
=====E ) Valeurs d'une variable internes ou externes à un script=====
====Pré-requis: utiliser la structure conditionnelle if====
À savoir :
* Opérateurs lexicographiques
* les opérateurs de comparaison numérique
====Exemples :====
La valeur (contenu) de la variable1 (var1) et de la variable2 (var2) peuvent être les arguments passés à un script.
Un script peut opérer un test sur les chaînes de caractères passées au script depuis le terminal.
(Lancez “mon-script” successivement sans argument, puis un, deux trois, etc. arguments.)
<code>
#!/bin/bash
var1=$1
var2=$2
echo $1
echo $2
if [ $# == 1 ] ; then
echo “ERREUR: vous avez entré $@, mais il faut deux arguments !”
elif [ $# == 2 ] ; then
echo “Les deux arguments que vous avez entré sont $1 et $2”
elif [ $# == 0 ] ; then
echo “ERREUR: vous n'avez pas entré d'arguments, il en faut deux !”
fi
</code>
Les chaînes testées par un script peuvent être aussi le contenu d'un fichier.
* Voir ce script : http://www.quennec.fr/linux/programmation-shell-sous-linux/les-bases-de-la-programmation-shell/ex%C3%A9cution-de-tests/la-5
Dans ces deux cas les valeurs des variables que l'on testent, sont choisies depuis l'extérieur du script (le script est un processus fils du shell).
Mais pour modifier la valeur d'une variable par un script (que le script appelle une valeur extérieure; chaîne de caractère donnée par le terminale, récupération du résultat d'une commande, contenu d'un fichier, etc. ou que cette variable soit affectée dans le script lui-même) on utilise les boucles.
=====F ) Déclaration nulle et modification par le script d'une valeur interne ou externe=====
Pré-requis : utiliser les structures de contrôle
Voir :
* boucle while
* boucle for
* boucle case
====Modifier la variable d'une structure de contrôle par une valeur appelée dans le script====
<code>
#!/bin/bash
for i in “$@”
do
echo “Vous avez donné à la variable 'i' la valeur : $i.”
if [ “$1” != “coucou” ] ; then
echo “Le premier argument doit être 'coucou'.”
else
echo “OK”
if [ “$2” != “toi” ] ; then
echo “Le deuxième paramètre doit être 'toi'.”
else
echo “MERCI”
fi
fi
done
echo ” ” #pour sauter une ligne
echo $@
</code>
Ci-dessus, la variable i de la boucle prend tour à tour la valeur des paramètres passé au script depuis le terminal et la structure if teste si la chaîne du paramètre passé au script (valeur de la variable) correspond au motif voulu.
====Modifier une variable déclarée dans le script par une structure de contrôle====
<code bash>
#!/bin/bash
set a b c
echo “Avec 'shift', on se décale d'un paramètre à chaque boucle.”
for i in “$@”
do
i=$1
shift 1
echo “les paramètres sont : $1 :$2 :$3 .”
done
</code>
Retour:
<code bash>
Avec 'shift', on se décale d'un paramètre à chaque boucle.
les paramètres sont : b :c : .
les paramètres sont : c : : .
les paramètres sont : : : .
</code>
=====G ) Déclarer des paramètres de position : set=====
==== syntaxe de set====
À savoir : variables de substitution prédéfinies bash-les-differents-caracteres-speciaux
*La commande set permet d'affecter une valeur provisoire à un ou plusieurs paramètres de position.
Les arguments de la commande set seront les valeurs des paramètres que set positionne.
<code>
set argument1 [argument2] …
</code>
<code bash>
#!/bin/bash
var=lettres
set a b c #affectation des paramètres a b c
echo “$var” “$1” “$2” “$3”
if [ $# != 2 ] ; then # (1)
echo “il y a trois paramètres et une variable nommée var de valeur \”lettres\“ ”
fi
</code>
Retour :
<code>
lettres a b c
il y a trois paramètres et une variable nommée var de valeur “lettres”
</code>
Observez:
* mon-script1
<code bash>
#!/bin/bash
set a b c
echo $@
echo “il y a les paramètres de position : $1, $2, $3”
echo “Leurs valeurs sont vide: RIEN”$a“, RIEN”$b“, RIEN”$c“.”
</code>
Retour :
<code bash>
a b c
il y a les paramètres de position : a, b, c
Leurs valeurs sont vide: RIEN, RIEN, RIEN.
</code>
====set annule les paramètres de position affectés précédemment====
<code bash>
#!/bin/bash
var=lettres
set a b c
echo $var
echo $@
echo “ ”
set gros_pater
echo $var
echo $1
set –
echo $var
echo $1
</code>
Retour :
<code>
lettres
a b c
lettres
gros_pater
lettres
</code>
====Paramètres de position et boucles====
Par exemple : soit le script ci-dessous boucle-set.sh
(passer un argument à ce script depuis le terminal)
<code bash>
#!/bin/bash
var=$1
echo $1
set a b c
#set –
echo $@
for i in “$@”
do
i=$1
echo “les paramètres sont : $1 :$2 :$3 .”
shift 1
echo $var
done
</code>
<code user>
./boucle-set.sh
</code>
Retour :
<code user>
a b c
les paramètres sont : a :b :c .
les paramètres sont : b :c : .
les paramètres sont : c : : .
~$
</code>
PUIS
<code user>
./boucle-set.sh argument1
</code>
retour :
<code>
argument1
a b c
les paramètres sont : a :b :c .
argument1
les paramètres sont : b :c : .
argument1
les paramètres sont : c : : .
argument1
</code>
=====H ) Supprimer les paramètres de position=====
====Exemple====
même script que ci-dessus mais on dé-commente set - - (on enlève # ligne 5) :
<code user>
./boucle-set.sh
</code>
retour :
<code>
~$
</code>
et
<code user>
./boucle-set.sh argument1
</code>
retour :
<code>
argument1
~$
</code>
====Attention à la commande set : les arguments passés au script sont supprimés====
Elle supprime toute possibilité de se référer à des paramètres passés au script (depuis le terminal),
et ceci y compris si on supprime avec set - - les paramètres de position déclarés avec set.
<code bash>
#!/bin/bash
#donner les argument 1 2 3 à se script avant de le lancer
var1=$1 ; var2=$2 ; var3=$3
echo “les valeurs de var1, var2 et var3 sont les paramètres de position : $@.”
echo “ ”
for i in “$@”
do
echo “les paramètres de position sont : $1 :$2 :$3 .”
shift 1
done
set a b c
set –
for i in “$@”
do
echo “les paramètres sont : $1 :$2 :$3 .”
done
echo “ ”
echo “les paramètres de position sont “$@”.”
echo “les valeurs 1, 2, et 3 sont maintenant les valeurs des variables $var1 ; $var2 ; $var3.”
</code>
Retour :
<code>
les valeurs de var1, var2 et var3 sont les paramètres de position : 1 2 3.
les paramètres de position sont : 1 :2 :3 .
les paramètres de position sont : 2 :3 : .
les paramètres de position sont : 3 : : .
les paramètres de position sont .
les valeurs 1, 2, et 3 sont maintenant les valeurs des variables 1 ; 2 ; 3.
</code>
====remarques sur set ====
<note >
*Sans argument la commande set affiche TOUS les noms et TOUTES les valeurs des variables pré-définies (celles du script qui l'appelle aussi). Mais elle n'enregistre pas une valeur d'un valeur non-déclarée !
<code bash>
#!/bin/bash
var=lettres
set a b c
set
</code>
Observons les deux dernières lignes du retour :
<code>
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
_=c
var=lettres
</code>
La première ligne montre en majuscule le nom d'une variable pré-défini, et ce qui suit est la valeur de cette variable.
Nous retrouvons la variable var de notre script avec sa valeur “lettres”.
Mais on ne voit pas les paramètres a b c.
*set -o nom-de-l'option ou set -abréviation-de-l'option: permet d'activer les options du shell dans un script.
Par exemple, on peut vérifier grâce à un message d'erreur si on appelle la valeur d'un paramètre qui n'a pas été défini.
<code bash>
#!/bin/bash
set -o nounset
var=a
var1=
echo $var
echo $var1
echo $var3
</code>
retour :
<code>
a
/home/hypathie/MesScripts/scriess: ligne8: var3 : variable sans liaison
</code>
Voir le tableau des options ici: http://abs.traduc.org/abs-5.3-fr/ch30.html#optionsref
</note>
=====I ) Les fonctions=====
====1) Définition d'une fonction====
Le shell bash permet plusieurs syntaxes pour définir une fonction.
Il faut utiliser le mot réservé function :
*syntaxe 1 :
<code>
function nom-de-la-fonction
{
suite-de-commande
}
nom-de-la-fonction
</code>
<note>
*entre les { } c'est le corps de la fonction ;
* on y place la ou les commandes exécuter par l'appel de la fonction;
* l'appel de la fonction se fait après sa définition;
* c'est le fait de mentionner le nom de la fonction qui l'appelle ou permet d'exécuter les commandes du corps de la fonction.
</note>
*Exemple :
<code bash>
#!/bin/bash
function f # on peut ajouter des parenthèse après le nom ; function f()
{
echo “Bonjour tout le monde”
}
f # retour : Bonjour tout le monde
</code>
<note>
Les mots réservés function et } doivent être les premiers d'une commande pour qu'ils soient reconnus.
Sinon il suffit de mettre ;avant } (avec un espace devant ;**)
</note>
#!/bin/bash function f { echo "coucou" ;} f # retour : coucou
#!/bin/bash function f { echo hello } f # retour : Hello
#!/bin/bash function f { echo $0 echo $USER echo $1 $2 $3 echo $# echo $@ echo $* } f chez debian facile #chez : premier argument #debian : deuxième argument #facile : troisième argument
Retour
/home/hypathie/MesScripts/script.fct hypathie chez debian facile 3 chez debian facile chez debian facile
Cette commande permet de décaler la numérotation des paramètres de position de la fonction
#!/bin/bash function minipoesie { echo "nom complet : $0" echo " " echo "$*" # avant 'shift 1' shift 1 (l'argument 1 est "chez") echo "$*" # après 'shift 1' echo "$*" # avant 'shift 2' shift 2 (l'argument 1 est "debian") echo -e "\t$*" # après 'shift 2' echo -e "\t $*" # avant 'shift 3' shift 3 echo -e "\t $*" # après 'shift 3' } minipoesie hypathie chez debian facile
retour
nom complet : /home/hypathie/MesScripts/minipoesie hypathie chez debian facile chez debian facile chez debian facile facile facile facile
Et voilà, vous devriez maintenant être capable de tout comprendre de l'exemple de ces liens: