Add bash trap article
This commit is contained in:
parent
af9f9b65be
commit
9e3e4729ab
7 changed files with 601 additions and 0 deletions
55
content/articles/2022/bash_les_pieges/files/message.sh
Normal file
55
content/articles/2022/bash_les_pieges/files/message.sh
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
DATE_FMT="+%s"
|
||||||
|
|
||||||
|
msg() {
|
||||||
|
local message="$*"
|
||||||
|
[ -z "$message" ] && return
|
||||||
|
if [ -t 1 ]
|
||||||
|
then
|
||||||
|
printf "%b\n" "$message"
|
||||||
|
else
|
||||||
|
log "$message"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
local message="${*-}"
|
||||||
|
[ -z "$message" ] && return
|
||||||
|
printf "%s %b\n" "$(date $DATE_FMT)" "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
debug() {
|
||||||
|
local message="$*"
|
||||||
|
[[ -z $DEBUG || $DEBUG -ne 1 ]] && return
|
||||||
|
[ -z "$message" ] && return
|
||||||
|
message="DEBUG [${BASH_SOURCE[1]}:${FUNCNAME[1]}]: $message"
|
||||||
|
if [ -t 2 ]
|
||||||
|
then
|
||||||
|
>&2 msg "\e[34m$message\e[0m"
|
||||||
|
else
|
||||||
|
>&2 log "$message"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
local message="$*"
|
||||||
|
[ -z "$message" ] && return
|
||||||
|
message="ERROR: $message"
|
||||||
|
if [[ -n $DEBUG && $DEBUG -eq 1 ]]
|
||||||
|
then
|
||||||
|
message="$message\n\tstack trace:\n"
|
||||||
|
for (( i=1; i<${#FUNCNAME[@]}; i++ ))
|
||||||
|
do
|
||||||
|
message="${message}\t source:${BASH_SOURCE[i]}"
|
||||||
|
message="${message} function:${FUNCNAME[$i]}"
|
||||||
|
message="${message} line:${BASH_LINENO[$i-1]}\n"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ -t 2 ]
|
||||||
|
then
|
||||||
|
>&2 msg "\e[31m$message\e[0m"
|
||||||
|
else
|
||||||
|
>&2 log "$message"
|
||||||
|
fi
|
||||||
|
}
|
49
content/articles/2022/bash_les_pieges/files/premier_script.sh
Executable file
49
content/articles/2022/bash_les_pieges/files/premier_script.sh
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
server="192.168.0.254 -i ~/.ssh/rick.epha.se.ed25519"
|
||||||
|
user="ephase"
|
||||||
|
|
||||||
|
# Reutilisons ce que nous avons créé lors du précédent article
|
||||||
|
source ./message.sh
|
||||||
|
|
||||||
|
ssh_sock="/tmp/$(mktemp -u XXXXXXXXXX)"
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
msg "Create SSH main connection wih socket ${ssh_sock}"
|
||||||
|
ssh -N -o ControlMaster=yes -o ControlPath="$ssh_sock" -f ${user}@${server} || {
|
||||||
|
error "Can't connect to $server";
|
||||||
|
exit 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_command() {
|
||||||
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
error "Launch command require 1 parameter"
|
||||||
|
exit 31
|
||||||
|
fi
|
||||||
|
local command
|
||||||
|
command="$1"
|
||||||
|
ssh -q -t -S "$ssh_sock" ${user}@${server} "$command" || {
|
||||||
|
error "";
|
||||||
|
exit 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
# close the master control connexion before
|
||||||
|
msg "Close SSH main connection"
|
||||||
|
ssh -q -o ControlPath="$ssh_sock" -O exit $server || {
|
||||||
|
error "Can't close SSH master connection, $ssh_sock remain";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connect
|
||||||
|
trap cleanup EXIT
|
||||||
|
if [ "$1" = "error" ]
|
||||||
|
then
|
||||||
|
launch_command
|
||||||
|
fi
|
||||||
|
for (( i=1; i<=5; i++ ))
|
||||||
|
do
|
||||||
|
launch_command "echo 'Message N°$i from $server'"
|
||||||
|
sleep 5
|
||||||
|
done
|
56
content/articles/2022/bash_les_pieges/files/second_script.sh
Executable file
56
content/articles/2022/bash_les_pieges/files/second_script.sh
Executable file
|
@ -0,0 +1,56 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
server="192.168.0.254 -i ~/.ssh/rick.epha.se.ed25519"
|
||||||
|
user="ephase"
|
||||||
|
|
||||||
|
# Reutilisons ce que nous avons créé lors du précédent article
|
||||||
|
source ./message.sh
|
||||||
|
|
||||||
|
ssh_sock="/tmp/$(mktemp -u XXXXXXXXXX)"
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
msg "Create SSH main connection wih socket ${ssh_sock}"
|
||||||
|
ssh -N -o ControlMaster=yes -o ControlPath="$ssh_sock" -f ${user}@${server} || {
|
||||||
|
error "Can't connect to $server";
|
||||||
|
exit 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_command() {
|
||||||
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
error "Launch command require 1 parameter"
|
||||||
|
exit 31
|
||||||
|
fi
|
||||||
|
local command
|
||||||
|
command="$1"
|
||||||
|
ssh -q -t -S "$ssh_sock" ${user}@${server} "$command" || {
|
||||||
|
error "";
|
||||||
|
exit 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
# close the master control connexion before
|
||||||
|
msg "Close SSH main connection"
|
||||||
|
ssh -q -o ControlPath="$ssh_sock" -O exit $server || {
|
||||||
|
error "Can't close SSH master connection, $ssh_sock remain";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process_int() {
|
||||||
|
error "Script interrupted by user (SIGINT)"
|
||||||
|
exit 255
|
||||||
|
}
|
||||||
|
|
||||||
|
connect
|
||||||
|
trap cleanup EXIT
|
||||||
|
trap process_int INT
|
||||||
|
if [ "$1" = "error" ]
|
||||||
|
then
|
||||||
|
launch_command
|
||||||
|
fi
|
||||||
|
for (( i=1; i<=5; i++ ))
|
||||||
|
do
|
||||||
|
launch_command "echo 'Message N°$i from $server'"
|
||||||
|
sleep 5
|
||||||
|
done
|
40
content/articles/2022/bash_les_pieges/files/test_ssh.sh
Executable file
40
content/articles/2022/bash_les_pieges/files/test_ssh.sh
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
server="192.168.0.254 -i ~/.ssh/rick.epha.se.ed25519"
|
||||||
|
user=ephase
|
||||||
|
|
||||||
|
source message.sh
|
||||||
|
|
||||||
|
ssh_sock="/tmp/$(mktemp -u XXXXXXXXXX)"
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
msg "Create SSH main connection wih socket ${ssh_sock}"
|
||||||
|
ssh -N -o ControlMaster=yes -o ControlPath="$ssh_sock" -f ${user}@${server} || {
|
||||||
|
# reuse
|
||||||
|
error "Can't connect to $server";
|
||||||
|
exit 210;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_command() {
|
||||||
|
local command
|
||||||
|
command="$1"
|
||||||
|
ssh -q -t -S "$ssh_sock" ${user}@${server} "$command"
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
# close the master control connexion before
|
||||||
|
msg "Close SSH main connection"
|
||||||
|
ssh -q -o ControlPath="$ssh_sock" -O exit ${server} || {
|
||||||
|
error "Can't close SSH master connection, $ssh_sock remain";
|
||||||
|
exit 21;
|
||||||
|
}
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
trap "cleanup 255" INT ERR
|
||||||
|
trap "cleanup" EXIT
|
||||||
|
connect
|
||||||
|
for (( i=10; i<=20; i++ ))
|
||||||
|
do
|
||||||
|
launch_command "echo 'Message N°$i from ${server}'"
|
||||||
|
sleep 1
|
||||||
|
done
|
65
content/articles/2022/bash_les_pieges/files/troisieme_script.sh
Executable file
65
content/articles/2022/bash_les_pieges/files/troisieme_script.sh
Executable file
|
@ -0,0 +1,65 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
server="192.168.0.254 -i ~/.ssh/rick.epha.se.ed25519"
|
||||||
|
user="ephase"
|
||||||
|
|
||||||
|
# Reutilisons ce que nous avons créé lors du précédent article
|
||||||
|
source ./message.sh
|
||||||
|
|
||||||
|
ssh_sock="/tmp/$(mktemp -u XXXXXXXXXX)"
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
msg "Create SSH main connection wih socket ${ssh_sock}"
|
||||||
|
ssh -N -o ControlMaster=yes -o ControlPath="$ssh_sock" -f ${user}@${server} || {
|
||||||
|
error "Can't connect to $server";
|
||||||
|
exit 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_command() {
|
||||||
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
error "Launch command require 1 parameter"
|
||||||
|
exit 31
|
||||||
|
fi
|
||||||
|
local command
|
||||||
|
command="$1"
|
||||||
|
ssh -q -t -S "$ssh_sock" ${user}@${server} "$command" || {
|
||||||
|
error "";
|
||||||
|
exit 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
# close the master control connexion before
|
||||||
|
msg "Close SSH main connection"
|
||||||
|
ssh -q -o ControlPath="$ssh_sock" -O exit $server || {
|
||||||
|
error "Can't close SSH master connection, $ssh_sock remain";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process_int() {
|
||||||
|
error "Script interrupted by user (SIGINT)"
|
||||||
|
exit 255
|
||||||
|
}
|
||||||
|
|
||||||
|
check_conn() {
|
||||||
|
msg "Check connection on ${server}"
|
||||||
|
ssh -S "$ssh_sock" -O check $server
|
||||||
|
sleep 20
|
||||||
|
}
|
||||||
|
|
||||||
|
msg "Current PID: $$"
|
||||||
|
connect
|
||||||
|
trap cleanup EXIT
|
||||||
|
trap process_int INT
|
||||||
|
trap check_conn USR1
|
||||||
|
|
||||||
|
if [ "$1" = "error" ]
|
||||||
|
then
|
||||||
|
launch_command
|
||||||
|
fi
|
||||||
|
for (( i=1; i<=20; i++ ))
|
||||||
|
do
|
||||||
|
launch_command "echo 'Message N°$i from $server'"
|
||||||
|
sleep 2
|
||||||
|
done
|
336
content/articles/2022/bash_les_pieges/index.md
Normal file
336
content/articles/2022/bash_les_pieges/index.md
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
Title: Bash avancé: les pièges (à signaux)
|
||||||
|
Category: sysadmin
|
||||||
|
Tags: bash, script, pl-fr
|
||||||
|
Date: 2022-11-15 8:30
|
||||||
|
Cover: assets/backgrounds/ackbar-trap.jpg
|
||||||
|
|
||||||
|
Pour l'instant, on ne peut pas dire que 2022 soit une année productive côté
|
||||||
|
article de blog. Le seul et unique article de cette année parlait de *Bash* qui
|
||||||
|
a eu un peu de succès. Comme toute les séries B un peu populaire, il lui fallait
|
||||||
|
une suite. Et bien la voici!
|
||||||
|
|
||||||
|
Dans cette suite, il va être question de faire un peu le ménage lorsque votre
|
||||||
|
script s'arrête, que se soit gracieusement ou pas, mais pas que...
|
||||||
|
|
||||||
|
## Dis, c'est quoi un signal
|
||||||
|
|
||||||
|
Un signal est ue sorte de notification envoyée à un processus lorsqu'un
|
||||||
|
événement particulier a eu lieu. Plus concrètement, lorsque un programme ne
|
||||||
|
réponds pas dans votre terminal et que vous faites Ctrl+C, le système envoi le
|
||||||
|
signal SIGINT au processus en cours lui signifiant d'interrompre séance tenante
|
||||||
|
toute action. Chaque signal est associé à un numéro
|
||||||
|
|
||||||
|
Voici un liste de quelques signaux (norme POSIX):
|
||||||
|
|
||||||
|
Signal | Valeur | Action | Commentaire
|
||||||
|
--------|--------|--------|----------------------------------------------------
|
||||||
|
SIGHUP | 1 | Term | Déconnexion du terminal ou fin du processus de contrôle
|
||||||
|
SIGINT | 2 | Term | Interruption depuis le clavier `CTRL + C`
|
||||||
|
SIGQUIT | 3 | Core | Demande ”Quitter” depuis le clavier `CTRL + \\`
|
||||||
|
SIGILL | 4 | Core | Instruction illégale
|
||||||
|
SIGABRT | 6 | Core | Signal d’arrêt depuis abort(3)
|
||||||
|
SIGFPE | 8 | Core | Erreur mathématique virgule flottante
|
||||||
|
SIGKILL | 9 | Term | Signal ”KILL”
|
||||||
|
... | ... | ... | ...
|
||||||
|
|
||||||
|
## Les utiliser dans Bash : trap
|
||||||
|
|
||||||
|
Paf, l'intrigue arrive comme ça d'un coup: nous allons utiliser la commande
|
||||||
|
`trap` pour gérer les signaux. La commande est plutôt simple à utiliser :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
trap "<commande>" <list_signaux>
|
||||||
|
```
|
||||||
|
|
||||||
|
Attention cependant, tous les signaux ne peuvent pas être piégé: `SIGKILL` par
|
||||||
|
exemple ne peut pas donner lieu à exécution d'une commande.
|
||||||
|
|
||||||
|
## Dans la vraie vie?
|
||||||
|
|
||||||
|
Prenons un cas concret: un script nécessite l'ouverture d'une connexion SSH en
|
||||||
|
persistante à l'aide des options `ControlMaster` et `ContolPath` histoire de
|
||||||
|
pouvoir lancer plusieurs connexions successives plus rapidement (et sans se
|
||||||
|
ré-identifier).
|
||||||
|
|
||||||
|
Si le script ne se passe pas comme prévu alors il est plutôt conseillé de faire
|
||||||
|
le ménage et terminer la connexion maitre.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Changer ces valeurs par celles adapté à votre configuration
|
||||||
|
server="192.168.0.254"
|
||||||
|
user="user"
|
||||||
|
|
||||||
|
# Réutilisons ce que nous avons créé lors du précédent article
|
||||||
|
source ./message.sh
|
||||||
|
|
||||||
|
ssh_sock="/tmp/$(mktemp -u XXXXXXXXXX)"
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
msg "Create SSH main connection wih socket ${ssh_sock}"
|
||||||
|
ssh -N -o ControlMaster=yes -o ControlPath="$ssh_sock" -f ${user}@${server} || {
|
||||||
|
error "Can't connect to $server";
|
||||||
|
exit 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_command() {
|
||||||
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
error "Launch command require 1 parameter"
|
||||||
|
exit 31
|
||||||
|
fi
|
||||||
|
local command
|
||||||
|
command="$1"
|
||||||
|
ssh -q -t -S "$ssh_sock" ${user}@${server} "$command" || {
|
||||||
|
error "Error executing $command";
|
||||||
|
exit 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
msg "Close SSH main connection"
|
||||||
|
ssh -q -o ControlPath="$ssh_sock" -O exit $server || {
|
||||||
|
error "Can't close SSH master connection, $ssh_sock remain";
|
||||||
|
}
|
||||||
|
# Sans ce exit, INT ne termine pas le script
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
connect
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
if [ "$1" = "error" ]
|
||||||
|
then
|
||||||
|
launch_command
|
||||||
|
fi
|
||||||
|
|
||||||
|
for (( i=1; i<=5; i++ ))
|
||||||
|
do
|
||||||
|
launch_command "echo 'Message N°$i from $server'"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce script se lance sans paramètre ou avec le paramètre error afin de générer une
|
||||||
|
erreur. Étudions le un peu.
|
||||||
|
|
||||||
|
La connexion principale est intiée par la fonction `connect`. Juste en dessous
|
||||||
|
de l'appel de cette dernière nous trouvons notre instruction `trap`. Elle
|
||||||
|
appelle la commande `cleanup` lorsque le signal `EXIT` est envoyé.
|
||||||
|
|
||||||
|
`EXIT` n'est pas un signal standards su système mais interne à *Bash* comme
|
||||||
|
`ERR`, `DEBUG` ou `RETURN`.
|
||||||
|
|
||||||
|
Ensuite, si l'argument `error` est passé à notre script, `launch_command` est
|
||||||
|
exécutée mais sans paramètre, ce qui ga générer une erreur.
|
||||||
|
|
||||||
|
Enfin notre script exécute 5 fois en boucle la fonction `laucun_command` qui
|
||||||
|
se charge d'afficher un petit message sur la machine distante en utilisant la
|
||||||
|
connexion SSH créée dans notre fonction `connect`.
|
||||||
|
|
||||||
|
Nous avons donc de quoi tester trois scénarios
|
||||||
|
|
||||||
|
### Laisser le script finir normalement
|
||||||
|
|
||||||
|
Appeler le script sans argument et le laisser se terminer sans intervenir est
|
||||||
|
notre premier scénario. Voici le résultat:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ ./script.sh
|
||||||
|
Create SSH main connection wih socket /tmp/TvCuLSzkMN
|
||||||
|
Enter passphrase for key '/home/user/.ssh/key.ed25519':
|
||||||
|
Message N°1 from 192.168.0.254
|
||||||
|
Message N°2 from 192.168.0.254
|
||||||
|
Message N°3 from 192.168.0.254
|
||||||
|
Message N°4 from 192.168.0.254
|
||||||
|
Message N°5 from 192.168.0.254
|
||||||
|
Close SSH main connection
|
||||||
|
```
|
||||||
|
|
||||||
|
Nous pouvons voir que notre fonction `cleanup` a bien été appelée à la fin de
|
||||||
|
notre script exécutée par le signal `EXIT`
|
||||||
|
|
||||||
|
### Générer une erreur
|
||||||
|
|
||||||
|
Maintenant passons `error` en paramètre et observons le résultat:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ ./script.sh error
|
||||||
|
Enter passphrase for key '/home/user/.ssh/key.ed25519':
|
||||||
|
Create SSH main connection wih socket /tmp/Al77btSXKf
|
||||||
|
ERROR: Launch command require 1 parameter
|
||||||
|
Close SSH main connection
|
||||||
|
```
|
||||||
|
|
||||||
|
`launch_command` appelée sans paramètre conduit à la sortie de notre script avec
|
||||||
|
un code supérieur à 0. Cette sortie est capturée par `trap` qui lance aussi la
|
||||||
|
fonction de nettoyage. Vérifions le code de retour de notre script:
|
||||||
|
|
||||||
|
```ssh
|
||||||
|
echo $?
|
||||||
|
31
|
||||||
|
```
|
||||||
|
|
||||||
|
Le code de retour est bien celui défini dans notre fonction `launch_command`
|
||||||
|
lorsqu'on l'exécute sans paramètre.
|
||||||
|
|
||||||
|
### Interrompre l'exécution
|
||||||
|
|
||||||
|
Enfin observons ce qui se passe lorsque l'on interrompt l'exécution du script avec
|
||||||
|
Ctrl+C:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ ./script.sh
|
||||||
|
Create SSH main connection wih socket /tmp/0gFlBD6siZ
|
||||||
|
Enter passphrase for key '/home/user/.ssh/key.ed25519':
|
||||||
|
Message N°1 from 192.168.0.254
|
||||||
|
Message N°2 from 192.168.0.254
|
||||||
|
^CClose SSH main connection
|
||||||
|
```
|
||||||
|
|
||||||
|
Ici encore tout se passe comme prévu, sauf que le code de retour est 0, il
|
||||||
|
faudrait pouvoir changer se comportement afin de signifier que le script ne
|
||||||
|
s'est pas termine comme prévu.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ echo $?
|
||||||
|
0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Différencier les pièges en fonction du signal
|
||||||
|
|
||||||
|
Tout est prévu dans *Bash* pour contourner ce problème: il est possible de
|
||||||
|
lancer plusieurs commandes `trap`. Dans notre script nous allons modifier un
|
||||||
|
petit peu notre script
|
||||||
|
|
||||||
|
### Gérer le signal `SIGINT`
|
||||||
|
|
||||||
|
Nous allons ajouter une fonction spécifique pour le signal juste après
|
||||||
|
`cleanup`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
process_int(){
|
||||||
|
error "Script interrupted by user (SIGINT)"
|
||||||
|
exit 255
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ajouter un piège
|
||||||
|
|
||||||
|
Maintenant nous n'avons plus qu'a ajouter un piège:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# [...]
|
||||||
|
trap cleanup EXIT
|
||||||
|
trap process_int INT
|
||||||
|
# [...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Et voilà, lors de l'exécution notre script et son interruption tout fonctionne
|
||||||
|
comme prévu:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ ./script.sh
|
||||||
|
Create SSH main connection wih socket /tmp/0gFlBD6siZ
|
||||||
|
Enter passphrase for key '/home/user/.ssh/key.ed25519':
|
||||||
|
Message N°1 from 192.168.0.254
|
||||||
|
Message N°2 from 192.168.0.254
|
||||||
|
^CERROR: Script interrupted by user (SIGINT)
|
||||||
|
Close SSH main connection
|
||||||
|
|
||||||
|
$ echo $?
|
||||||
|
255
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vérifier la connexion au master avec un signal
|
||||||
|
|
||||||
|
Il est possible d'utiliser tout un tas de signaux et de les intercepter avec
|
||||||
|
`trap`. Intéressons nous maintenant à `SIGUSR1`. C'est avec `SIGUSR2` des
|
||||||
|
signaux servant pour ce que l'on veut. Nous voulons afficher l'était de la
|
||||||
|
connexion SSH master. Rajoutons la fonction suivante après `launch_command`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# [...]
|
||||||
|
check_conn() {
|
||||||
|
msg "Check connection on ${server}"
|
||||||
|
ssh -S "$ssh_sock" -O stop $server
|
||||||
|
sleep 10
|
||||||
|
}
|
||||||
|
#[...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Puis de modifier le début de notre script comme ceci:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# [...]
|
||||||
|
msg "Current PID: $$"
|
||||||
|
connect
|
||||||
|
trap cleanup EXIT
|
||||||
|
trap process_int INT
|
||||||
|
trap check_conn USR1
|
||||||
|
# [...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Au début nous affichons le PID de notre script, nous allons en avoir besoin pour
|
||||||
|
lui envoyer le signal `USR1` avec `kill` depuis un autre terminal. Et enfin
|
||||||
|
piégeons notre signal avec `trap` pour exécuter `check_conn`.
|
||||||
|
|
||||||
|
Afin de disposer de plus de temps pour lancer la commande kill
|
||||||
|
|
||||||
|
Afin d'avoir le temps de lancer la commande `kill`, augmentons de 20 le nombre
|
||||||
|
de tour de boucle effectué comme ci-dessous:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# [...]
|
||||||
|
|
||||||
|
for (( i=1; i<=20; i++ ))
|
||||||
|
do
|
||||||
|
launch_command "echo 'Message N°$i from $server'"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lancer le script
|
||||||
|
|
||||||
|
D'abord lançons le script et notons le numéros de PID:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ ./sscript.sh
|
||||||
|
Current PID: 9499
|
||||||
|
Create SSH main connection wih socket /tmp/A4IdltbuxY
|
||||||
|
Enter passphrase for key '/home/user/.ssh/key.ed25519':
|
||||||
|
Message N°1 from 192.168.0.254
|
||||||
|
```
|
||||||
|
Puis dans un second terminal il nous suffit d'envoyer le signal:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kill -USR1 9499
|
||||||
|
```
|
||||||
|
|
||||||
|
Le signal est alors reçu par notre script qui va donc exécuter la fonction
|
||||||
|
attachée:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
[...]
|
||||||
|
Message N°6 from 192.168.0.254
|
||||||
|
Message N°7 from 192.168.0.254
|
||||||
|
Check connection on 192.168.0.254
|
||||||
|
Master running (pid=9502)
|
||||||
|
```
|
||||||
|
|
||||||
|
Et continuer son exécution ensuite.
|
||||||
|
|
||||||
|
## En conclusion
|
||||||
|
|
||||||
|
Tout au long ce cet article, nous avons vu ce qu'était un signal et comment en
|
||||||
|
intercepter un (et même plusieurs) dans un script écrit en Bash. Bien entendu il
|
||||||
|
est possible d'utiliser les signaux dans d'autre langages, la façon de procéder
|
||||||
|
est similaire.
|
||||||
|
|
||||||
|
Le nettoyage des traces laissées par un script qui ne se termine pas de la façon
|
||||||
|
attendue est la principale utilisation documentée ci et là dans différents
|
||||||
|
tutoriaux. Mais ce peut être un outils intéressant de communication
|
||||||
|
inter-processus dans vos scripts.
|
BIN
content/assets/backgrounds/ackbar-trap.jpg
Normal file
BIN
content/assets/backgrounds/ackbar-trap.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
Loading…
Add table
Add a link
Reference in a new issue