# Script

Faire un script Linux pour automatiser ou industrialiser des commandes

# Faire un script Linux

### Comment faire un script Linux ?

#### <span style="font-weight: 400;">Création du fichier</span>

<span style="font-weight: 400;">Créer un fichier `monFichier.sh` : </span>

```shell
nano monFichier.sh
```

<p class="callout info">L'extension ".sh" n'est pas obligatoire. Elle permet juste d'indiquer le type de fichier.</p>

#### <span style="font-weight: 400;">Contenu du script</span>

<p class="callout success">Tous les script linux devront commencer par `<strong><em>#!/bin/bash</em></strong>`</p>

**Paramètre Shell**

<table id="bkmrk-param%C3%A8tres-fonction-" style="width: 69.3827%;"><tbody><tr><td style="width: 17.5926%;">**Paramètres**

</td><td style="width: 82.4074%;">**Fonction**

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">$1-$9</span>

</td><td style="width: 82.4074%;">Représente les paramètres positionnels pour les arguments 1 à 9

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">${10}-${n}</span>

</td><td style="width: 82.4074%;">Représente les paramètres positionnels pour les arguments après 9

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">$0</span>

</td><td style="width: 82.4074%;">Représente le nom du script

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">$∗</span>

</td><td style="width: 82.4074%;">Représente tous les arguments comme une seule chaîne de caractères

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">$@</span>

</td><td style="width: 82.4074%;">Identique au $∗, mais différent lorsqu'il est entouré de (").

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">$#</span>

</td><td style="width: 82.4074%;">Représente le nombre total d'argument

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">$$</span>

</td><td style="width: 82.4074%;"><span style="font-weight: 400;">PID du script</span>

</td></tr><tr><td style="width: 17.5926%;"><span style="font-weight: 400;">$?</span>

</td><td style="width: 82.4074%;"><span style="font-weight: 400;">Représente le dernier code retourné </span>

</td></tr></tbody></table>

#### Exécution du script

Pour exécuter un fichier ".sh" :

```shell
bash monFichier.sh
```

> Si vous souhaitez exécuter un script sans utiliser la commande `bash`. Vous pouvez le faire en vous rajoutant les droits d'exécution sur le fichier.

Ce qui donne la commande suivante :

```shell
chmod +x monFichier.sh
```

Vous pouvez désormais exécuter le script de la manière suivante :

```shell
./monFichier.sh
```

#### Exemple script 

Voici un exemple d'un script qui afficher des informations :

```shell
#!/bin/bash

# Ceci est un commentaire en bash

# Afficher le mot "Hello world"
echo "Hello world"

# Afficher le nom du script
echo $0
```

La sortie du script :

```
user@server:/home/user$ ./monFichier.sh
Hello world
./monFichier.sh
```

# Script de sauvegarde

##### Prérequis :

- avoir un accès ssh sur un serveur de sauvegarde
- avoir installé [rsync](http://doc.ubuntu-fr.org/rsync) sur la machine et le serveur
- avoir installé zenity

##### Fonctionnalités :

- juste besoin de lister les dossiers et fichiers à sauvegarder dans un fichier texte une fois le script configuré
- vérifie l'état de la connexion et fait un ping sur le serveur avant la sauvegarde
- crée un log hebdomadaire des fichiers sauvegardés
- affiche une jolie notification à la fin de la sauvegarde
- si on clique sur l'icone de notification, affiche la liste des fichiers sauvegardés

Voici le contenu du script

```shell
#!/usr/bin/env bash
# rsync from this host to the backup server

#options de sauvegarde manuelle interactive
if [ "$*" = "-m" -o "$*" = "--manual" ]; then
	MODE="Manual"
else
	MODE="Automatic"
fi

#vérification de la connection réseau et boucle en attente de connexion
# eth est à adapter en fonction du nom de votre carte réseau, ici eth pour eth0 + eth1 (ethernet ou wifi)
ETH="eth"
WAIT=0
while [ `ifconfig | grep -A1 ${ETH} | sed -n 's/.*adr:\([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' | wc -c` = 0 ]; do
	WAIT=1
	sleep 5
	echo waiting
done
#laisse un peu de temps si la connexion était coupée
if [ ${WAIT} = 1 ]; then
	sleep 5
fi

#définition des variables
#------------------------
SCRIPT_PATH=~/scripts/backup		#chemin du dossier contenant le script
SRC_FOLDER=~/					#chemin du dossier local contenant les fichiers à sauvergarder
SAVELIST=${SCRIPT_PATH}/savelist	#fichier texte contenant la liste des fichiers et sous-dossiers de SRC_FOLDER à sauvegarder
#------------------------ 
USER=nom_utilisateur				#nom d'utilisateur ssh sur le serveur
REMOTE_HOST=server.domain.fr		#adresse distante du serveur de sauvegarde
ALT_HOST=server.local				#adresse locale du serveur de sauvegarde
DST_FOLDER=backup				#nom du dossier de sauvegarde sur le serveur
#------------------------
NICE=5					#priorité donnée au script
#------------------------

#teste si on est en local, auquel cas changement de nom de serveur
ping -c 2 -d ${ALT_HOST} && REMOTE_HOST=${ALT_HOST}

LOGIN=${USER}@${REMOTE_HOST}
DATE=`date +%k:%M`

#création du dossier de log si inexistant
if [ ! -e ${SCRIPT_PATH}  ] ; then mkdir ${SCRIPT_PATH}/log; touch ${SCRIPT_PATH}/log/last ; fi

#fonction de notification
notification() {
	# ${1} = "terminée" ou "annulée"
	# ${2} = durée d'affichage en secondes
	echo message:"${DATE}\nLa sauvegarde sur ${REMOTE_HOST} est ${1}" | zenity --notification --listen --window-icon="info" | zenity --notification --timeout=${2} --window-icon="info" --text="Sauvegarde sur ${REMOTE_HOST} ${1} (${DATE})" && if cat ${SCRIPT_PATH}/log/list | grep ""; then cat ${SCRIPT_PATH}/log/list | grep -v /$ | zenity --text-info --title="Fichiers synchronisés" --width=800 --height=600; else zenity --info --text="Aucun fichier synchronisé"; fi

}

#fonction de sauvegarde et log
save() {
	#synchronisation et log
	{
	echo "# ${MODE} backup"
	echo "# Starting: "`/bin/date`
	nice -n ${NICE} rsync -avrz --delete \
	--files-from=${SAVELIST} \
	${SRC_FOLDER} \
	${LOGIN}:${DST_FOLDER}
	echo "# Ending: "`/bin/date`
	echo "# -------------------------------------------------------------"
	echo
	} >> ${SCRIPT_PATH}/log/`date +%G-%V`.log
	date >> ${SCRIPT_PATH}/log/last
	#sauvegarde du nom des derniers fichiers synchronisés
	tac ${SCRIPT_PATH}/log/`date +%G-%V`.log | sed -n '2,/#\ -/p' | tac | sed -e '1,5d' | sed -e :a -e '$d;N;2,5ba' -e 'P;D' >${SCRIPT_PATH}/log/list
	#notification
	notification "terminée" 1200
}

#dialogue si mode interactif
if [ ${MODE} = "Automatic" ]; then
	save	
else
	zenity --question --title="Sauvegarde Manuelle sur ${REMOTE_HOST}" --text="Sauvegarder sur ${REMOTE_HOST} maintenant?

	La dernière sauvegarde date du :
	`tail -1 ${SCRIPT_PATH}/log/last | sed 's/ (UTC.*//'`
	Les modifications ultérieures seront tranférées sur ${REMOTE_HOST}.
	"

	if [ $? = "0" ]
	then
		save
	else
		notification "annulée" 60
	fi
fi
```

rendez ensuite le script exécutable

```shell
chmod u+x /chemin/vers/backup.sh
```

adaptez la partie du script contenant les variables à votre configuration

```shell
#définition des variables
#------------------------
SCRIPT_PATH=~/scripts/backup		#chemin du dossier contenant le script
SRC_FOLDER=~/					#chemin du dossier local contenant les fichiers à sauvergarder
SAVELIST=${SCRIPT_PATH}/savelist	#fichier texte contenant la liste des fichiers et sous-dossiers de SRC_FOLDER à sauvegarder
#------------------------ 
USER=nom_utilisateur				#nom d'utilisateur ssh sur le serveur
REMOTE_HOST=server.domain.fr		#adresse distante du serveur de sauvegarde
ALT_HOST=server.local				#adresse locale du serveur de sauvegarde
DST_FOLDER=backup				#nom du dossier de sauvegarde sur le serveur
#------------------------
NICE=5					#priorité donnée au script
#------------------------
```

et créez le fichier contenant la liste des dossiers à sauvegarder (ici /chemin/vers/savelist )  
/!\\ les fichiers et dossiers listés sont des sous-fichiers/dossiers du dossier défini auparavant par SRC\_FOLDER (par défaut le home)  
/!\\ attention à la casse des caractères

```
Documents/Travail
Images/Travail
autres/dossier_super_important
```

Pour lancer le script

```
/chemin/vers/backup.sh
```

pour le lancer avec une boîte de dialogue de confirmation (j'ai fait un lanceur sur le tableau de bord avec la commande "bash /chemin/vers/backup.sh --manual")

```
/chemin/vers/backup.sh --manual
```

et enfin pour automatiser les sauvegardes, il faut utiliser [cron](http://doc.ubuntu-fr.org/cron)

```shell
crontab -e
```

et ajouter les paramètres suivants pour lancer le script à midi du lundi au vendredi (le &gt;&gt;/chemin/vers/log/cronlog 2&gt;&amp;1 permet de créer un log pour debugger)

```shell
DISPLAY=":0.0"
USER="nom_utilisateur"
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h  dom mon dow   command
00 12 * * 1-5 /chemin/vers/backup.sh >>/chemin/vers/log/cronlog 2>&1
```

# Commande en arrière plan

## Comment exécuter une commande en tâche de fond ? 

##### Exécuter une commande Linux en arrière-plan

Pour exécuter une commande en arrière-plan, ajoutez le symbole esperluette ( `&`) à la fin de la commande :

```bash
command &
```

L'ID du travail shell (entouré de crochets) et l'ID du processus seront imprimés sur le terminal :

```bash
# Output
[1] 25177
```

<p class="callout warning">Cependant le processus en arrière-plan continuera à écrire des messages sur le terminal à partir duquel vous avez appelé la commande.</p>

Pour supprimer les messages `stdout`et `stderr`, utilisez la syntaxe suivante :

```bash
command > /dev/null 2>&1 & 
```

##  

## Screen ?