------------
Programmation bash
------------

Introduction :

Tos au tard le linuxien aura besoin de programmer un pti script en bash (shell script in english) pour automatiser des taches ou autre (pour crée ses règles iptables a chaque démarrage par exemple , ou encore pour effectuer des opérations sur des fichiers) enfin tous ce que vous pourrez en trouver comme utilité . Dans ce premiers et bref tutos nous verrons les bases du shell script (on fera des exercices pour que vous ne vous ennuyez pas vous inquiétez pas ;)) .

Au programme : 

I/Connaissance minimale sur un script shell 
-Création d'un shell script et le rendre exécutable
-Structure d'un script bash
-Déclaration et utilisation de variable


II/Poussons un peu le bouchons

-Commande de bases
-Variable spéciale
-Structures de contrôle (if , else et case)
-Boucles (while , for)
-Petit exemple

III/Allez pour les moins paresseux on continue sur la lancer
-Manipulation des paramètre
-Gestion de signaux
-Un autre petit exemple

Allez on est parti ;)

I/Connaisance minimale sur un script shell :

   1-1/Creation d'un shell script et le rendre executable :

Pour cree un shell script rien de plus simple , il faut cree un fichier ascii qui ne contient pas d'extension ou l'extension .sh si vous voulez vous y retrouvez et encore . Nous allons par exemple cree le fichier "exp1" donc dans notre shell "touch exp1" (ont peut faire d'une autre maniere mais nous on fais comme ca ..) une fois cree pour que le systeme "sache" qu'il faut l'executer nous allons tous le rendre executable . Pour cela nous utiliserons chmod :

touch exp1   #ont crée le fichier exp1
chmod +x exp1 #ont rend le fichier exp1 executable

Voila notre pre-script est considerer comme executable et on peut commencer a travailler

   1-2/Structure d'un script bash :

Un shell script (et oui je speak english moi) devras toujours commencer par un ShiBang (#!) (ce n'est pas obligatoire mais c'est quand meme plus propre) cela permet au shell de "savoir" qu'elle programme elle doit utiliser pour interpreter le script , dans notre cas nous utiliserons bien sur le shell pour interpreter notre script donc nous commencerons toujours notre script par un :

#!/bin/bash
#ce qui suit le shibang est le chemin du programe qui doit l'interpreter

Les commentaire sont comme en php , ils sont précédes d'une diese (#), ils ne serons pas interpreter mais vous permetent de vous y retrouver quand vous n'avez pas mis le nez dans un script depuis pas mal de temps par exemple (et oui faut faire un exemple pour les plus lents :P)

#ceci ne sera pas interpreter

Bon allez on commence enfin a s'interesser en la programmation en elle meme

   1-3/Declaration et utilisation de variable :

Pour declarer une variable rien de plus simple , il sufit d'ecrire le nom de la variable et de la faire preceder de ="valeur" pour lui afecter "valeur" , une fois declarer l'utiliser est souvent utile ^^ , pour l'utiliser il vous sufit de faire preceder le nom de la variable que vous avez declarer par un dollard ($) , bon allez vu que j'explique mal un petit exemples s'impose :

#!/bin/bash
#J'espere que vous n'avez pas deja oublier a quoi servait le Shibang ;)

VAR1="Valeur1"
VAR2="Valeur2"

echo "la variable 1 contien $VAR1 et la variable 2 contient $VAR2"
#echo permet d'aficher quelque chose sur la sortie standart (l'ecran)

Ce mini script afichera "la variable 1 contien Valeur1 et la variable 2 contient Valeur2" , ca n'a aucune utilité mais la vous avez compris au moins , les exemples et les exercices sont le meileur moyens de retenir donc faites les tous les deux ;)

II/Poussons un peu le bouchons :

   2-1/Commande de bases :

Source : http://www.linuxfocus.org/Francais/September2001/article216.shtml (et oui je suis paresseux ;))

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, USA

Le résultat sera :
Adam Bor, India
Kerry Miller, USA

Vous pouvez faire beaucoup plus avec awk mais ce qui précède est l'usage le plus courant.

   2-2/Variable speciale:

Lorsqu'un shell interprete un shell script il initialise certaine variable , dites speciales , qui ne sont accessibles que en lectures seulement et qui permettent au shell scripteur . Voila une liste des variables speciales (celle la je l'ai faites car je suis quand meme pas paresseux a ce point :

$$ Contient le PID du script , il peut vous servir par exemple quand vous voulez ensuite faire un kill sans le chercher .. (c'est plus utile que l'ont ne le crois)
$? Cette variable changera tous au long du script , elle contiendera le code de retour de la dernier fonction (A note que si elle est egale a 0 c'est que la fonction c'est derouler sans encombre)
$* Ensemble des parametre passer lors de l'appel de script
E xemple : Pour un appel ./script arg1 arg2 la variable $* contiendera ./script arg1 arg2
$# Contient le nombre d'argument passer lors ed l'appel
E xemple : Lors de l'appel de script precedant $# contiendera 3
Variables positionels Ce sont les variable qui designe l'argument ,
Toujours en suivant l'exemple: (et oui j'aime bien mon exemple) de l'appel precedant $0 contiendera ./script $1 contiendera arg1 et $2 contiendera arg2

   2-3/Structures de controle (if , else et case) :

Dans n'importe qu'elle script il est tres utile , voir meme indispensable d'utiliser des structures de controle pour controler (c'etais dur a deviner ca non ?) , dans ce paragraphe ont expliquera les if , else , et case .

If : Permet de faire des verification sur a peu pres tous ce que ont peut imaginer :

if instructions
then
  #1er bloc d'instructions
else
  #2nd bloc d'instructions
fi

if (en anglais "si") si l'intruction ou les instructions (il peux y en avoir plusieurs) renvoi vrai alors les instructions qui figure dans then (en anglais "quand") seront execute alors que si ces instructions renvoi faux alors les instructions figurant dans le else seront executer (en anglais "sinon") . Bon vu que j'arrive pas du tout a expliquer ca je vais l'illustrer par un petit exemples

#!/bin/bash

var1 = 2
var2=1
if var1 > var2
then
echo "$var1 est bien superieur a $var2"
else
echo "Euhh la y a un leger probleme"
fi

Si au lieu d'instructions vous souhaitez comparez le resultat a diverses possibilites alors il serais plus simple , plus propre et plus rapide d'utiliser l'instruction case , cette fois je vais meme pas essayer d'expliquer donc un exemple sufira :

case $variable in
 valeur1)
  #1er bloc d'instructions
  ;;
 valeur2)
  #2ème bloc d'instructions
  ;;
 valeur3)
  #3ème bloc d'instructions
  ;;
 *)
  #Traitement des autres valeurs
  ;;
esac

Entre case et in se trouve la chaîne à comparer
si variable est egale a valeur1 alors le 1 blog d'instructions s'executera
si variable est egale a valeur2 alors le 2 blog d'instructions s'executera
...
esac : fin du blod de test :

   2-4/Boucles (while , for) :

On a parfois de faire le meme traitement plusieurs fois de suite , c'est meme plus souvent que parfois ;) , pour cela nous pouvons utiliser les boucles while et for qui permettent de repter une operation plusieurs fois de maniere controler . Bon apres une chtites introduction comme ca on va commencer par expliquer la synthaxe de la boucle while pour ensuite continuer sur la lancer avec la boucle for . Apres pour que vous ne soyez pas trop perdu nous etudierons un petits exemple .

Pour le while le traitement est repeter tant que l'instruction est vrai :

while instructions
do
  # Traitement à répéter
done

Tant que l'instructions est vrai alors le traitement est repter , (on peut faire le contraire avec until et la synthaxe est la meme) , la fin des instructions a repteter sont situer grace au done .

Le for est legerement differend car le nombre d'iteration est deja connu a l'avance , de meme la synthaxe de for est largement diferentes de while et until :

for variable in liste_de_valeurs
do
  # Traitement à répéter
done

La liste suivant le in est constituée de plusieurs valeurs séparées par des espaces. Le traitement sera alors répété et on aura accès à $variable qui prendra successivement ces valeurs dans l'ordre indiqué. Dès que toutes les valeurs auront été parcourues, la boucle s'arrêtera. . Bon allez un petits exemple s'impose :

   2-5/Petit exemple

A note que le ! signifie diferend en programmation

!#/bin/bash
#cette exemple renomera certains fichiers fichiers
#premier if si $1 n'existe pas on affiche un message d'erreur
#et on quite le script avec l'etat 1
if [ !$1 ]
 then
  echo "Usage du script :"
  echo "$0 Nom_du_repertoire"
  exit 1
fi
DIR=$1
#verifie si ce que contient dir est un repertoire
if [ -d $DIR]
 then
  echo "$DIR est bien un repertoire .."
 else
  echo "$DIR n'est pas un repertoire"
  exit 1
fi
#une fois ces verification nous allons renomer les fichier du repetoire choisi une #premier fois qui contient des majucule en minuscule

for a in `ls $DIR`
 do
  newname=`echo $a | tr A-Z a-z`
  mv $DIR/$a $DIR/$newname
 done
#et ensuite chercher les sous repertoire et faire pareil
for SREP in `find -type d`
 do
  for a in $SREP
   do
   if [ -f $a ]
    then
     newname=`echo $a | tr A-Z a-z`
     mv $a $newname
    fi
   done
  done