#1 Le 20/06/2013, à 20:06
- Zolotaya
[Script] Variable partagée entre plusieurs scripts
Bonjour à tous,
J'ai actuellement un petit problème de scripting et je cherche quelqu'un qui aurait une idée pour le résoudre.
La situation est la suivante :
J'ai fait un NAS maison qui tourne actuellement 7/7, 24/24. Seule problème : Ma facture d’électricité a explosé ...
Je souhaite donc éteindre mon NAS quand je ne l'utilise pas.
1ere solution : se connecter en ssh puis faire un "halt" --> pas pratique
2eme solution : un cron avec un halt tous les jours à 2h --> pas pratique non plus
3eme solution : un script maison qui détecte tout seul la consommation de la bande-passante et si il fait rien depuis x temps, il s'éteint tout seul.
J'ai donc commencé à écrire le bout le code à la fin de ce poste
L'idée est la suivante :
à l'aide de vnstat, je calcul le trafic réseau toutes les 5 secondes.
Je met dans un tableau le total de Kbits utilisé pendant ces 5 dernières secondes.
De cette façon, je peux retrouver exactement quel a été le trafic il y a 3 heure pour une durée déterminé genre 5 minutes / 30 minutes, la dernière heure, les 15 dernières secondes ...
Je peux donc faire facilement une règle qui dit :
Si le NAS a un trafic inférieur à 10Mbits la dernière heure et 1Mbits la dernière minutes et 10kbits les 10 dernières secondes alors il s’arrête
Le truc c'est que j'aurais voulu déporté cette règle la dans un autre script qui serait appelé par un crontab (genre toutes les 15 minutes)
Mon soucis c'est qu'en faisant ça, je ne peux pas récupérer la valeur de mes variables qui sont mises à jour dans le script ci-dessous. Si quelqu'un a une idée, je suis preneur.
#---- Functions ----#
usage(){
cat << EOF
usage: $0 options
This script save the network usage for a specific delay time.
OPTIONS:
-h Show this help message
-i Define a specific interface (ex : eth0).
-d Delay of recording network usage history in minutes. Default 24 hours
EOF
exit 1
}
#---- Script ----#
declare -a RECV_HISTORY
declare -a SEND_HISTORY
export SEND_HISTORY
export RECV_HISTORY
export HISTORY_SIZE
export HISTORY_START
export HISTORY_END
DELAY=1440
#-- Script start here
while getopts :i:d:h option
do
case "${option}"
in
i) IFACE=${OPTARG};;
d) DELAY=${OPTARG};;
h) HELP=1;;
\?) echo "Invalid option: -$OPTARG" >&2
HELP=1;;
:) echo "Invalid option: -$OPTARG ; require an argument" >&2
HELP=1;;
esac
done
vnstat > /dev/null
RET=`echo $?`
if [[ ${RET} -ne 0 ]] ; then
echo "The command vnstat is required to launch this script" >&2
exit 1
fi
if [ -n "$HELP" ] ; then
usage
fi
# Set specific interface
if [ -n "$IFACE" ] ; then
IFACE=" -i ${IFACE}"
fi
HISTORY_SIZE=`echo $DELAY \* 60 / 5 | bc`
HISTORY_START=0
HISTORY_END=0
while true
do
NETWORK_USAGE=`vnstat ${IFACE} -tr`
# retreive bandwith used the last 5th seconds
RECV_DATA=`echo ${NETWORK_USAGE} | sed -e 's/.*rx \([[:digit:]][[:digit:]]*\.[[:digit:]][[:digit:]]\) kbit.*/\1/' -e 's/.*rx \([[:digit:]][[:digit:]]*\.[[:digit:]][[:digit:]]\) Mbit.*/\1 \* 1024/'`
SEND_DATA=`echo ${NETWORK_USAGE} | sed -e 's/.*tx \([[:digit:]][[:digit:]]*\.[[:digit:]][[:digit:]]\) kbit.*/\1/' -e 's/.*tx \([[:digit:]][[:digit:]]*\.[[:digit:]][[:digit:]]\) Mbit.*/\1 \* 1024/'`
# Compute using data
RECV_DATA=`echo $RECV_DATA \* 5 | bc `
SEND_DATA=`echo $SEND_DATA \* 5 | bc `
echo "-----"
echo "received data : ${RECV_DATA}"
echo "sended data : ${SEND_DATA}"
# Adding at the end of the array
SEND_HISTORY[${HISTORY_END}]=${SEND_DATA}
RECV_HISTORY[${HISTORY_END}]=${RECV_DATA}
# Free memory over history size
if [[ ${#SEND_HISTORY[*]} -gt ${HISTORY_SIZE} ]] ; then
unset RECV_HISTORY[${HISTORY_START}]
unset SEND_HISTORY[${HISTORY_START}]
HISTORY_START=`expr ${HISTORY_START} + 1`
fi
HISTORY_END=`expr ${HISTORY_END} + 1`
done
Je reste à votre disposition si vous avez des questions
Merci par avance pour vos réponses
Zolotaya.
Hors ligne
#2 Le 20/06/2013, à 20:20
- amj
Re : [Script] Variable partagée entre plusieurs scripts
Salut
je pense que c'est ceci que tu cherche http://fr.wikibooks.org/wiki/Programmat … ironnement
donc
export VAR
Est-ce qu'un raspberry pi (3W) ne conviendrais pas? (ça dépend de la quantité de donné à stoker sans doute.)
quand ça viens de la doc c'est encore mieux
export [-fn] [name[=word]] ...
export -p
The supplied names are marked for automatic export to the envi‐
ronment of subsequently executed commands. If the -f option is
given, the names refer to functions. If no names are given, or
if the -p option is supplied, a list of all names that are
exported in this shell is printed. The -n option causes the
export property to be removed from each name. If a variable
name is followed by =word, the value of the variable is set to
word. export returns an exit status of 0 unless an invalid
option is encountered, one of the names is not a valid shell
variable name, or -f is supplied with a name that is not a func‐
tion.
(export -p reviens plus ou moins au même que env)
Dernière modification par amj (Le 20/06/2013, à 20:37)
Vive le logiciel libre !! Articles aléatoires sur Wikipédia sur les logiciels libre, sur linux.
Hors ligne
#3 Le 20/06/2013, à 21:35
- Zakhar
Re : [Script] Variable partagée entre plusieurs scripts
Salut Zolotaya,
eh oui, la consommation électrique... C'est pour ça que les vendeurs de NAS existent et font attention à ce genre de chose.
Mon Synology consomme environ 30W avec ses 4 disques en marche, et presque rien en hibernation. Or, le calcul financier est vite fait, j'arrondis de la façon suivante :
1W = 1€ / an
(en fait c'est légèrement plus, mais ça donne une idée simple).
Pour ton "partage de variable", c'est tout simplement impossible comme tu l'entends... et heureusement que c'est impossible !
Tu vas comprendre, c'est assez simple en fait : ton shell qui suit le trafic réseau, et le shell que sera lancé dans le cron sont deux process totalement indépendants. Il ne peuvent donc absolument pas partager des "variables" si tu entends par là une zone mémoire où est stockée une valeur.
L'export cité ci-dessus ne marchera pas. L'export fonctionne quand tu es par exemple dans ta console, tu lances un script qui veut 'setter' une variable, mais tu veux que cette variable persiste après la fin du script en cours parce que tu en as besoin dans les scripts suivants.
Si tu te contentes de mettre une valeur dans la variable, la variable et sa valeur seront perdues quand le script en cours dans ta console se termine.
Au contraire, si le script en cours fait un export, lorsqu'il se termine, le "parent" (ici la console) voit encore la variable.
Mais l'export ne fonctionne qu'avec ton parent, et pas avec deux scripts qui n'ont aucun rapport et ne sont pas lancés par le même "parent".
Pour faire ce "partage", il faut que tu passes pas un élément commun entre ces deux process totalement indépendants.
L'idée la plus simple est alors de passer par un fichier.
Si tu veux éviter les accès disques, tu peux mettre le fichier sur /dev/shm, ou tout répertoire monté en tmpfs.
Le shell qui calcule l'activité écrit un fichier.
Le cron lit le fichier.
Pour que ce soit simple, le 1er shell peut écrire ça sous forme de morceau de code directement exploitable par le second, par exemple :
last5min=12345
last1h=147859
# etc....
Ainsi le cron peut simplement 'sourcer' ce fichier pour récupérer les variables.
Ce n'est qu'une façon de faire. Elle a le mérite d'être simple... mais n'est pas exempte de problèmes. Par exemple un 'attaquant' peut remplir ton fichier avec des valeurs pour provoquer l'arrêt de ton PC (denial of service)... Parade : si tes deux scripts sont lancés en root, bien gérer les droits du fichier d'échange. Ainsi l'attaquant devra déjà avoir les droits roots... et s'il les a déjà, il peut de toute façon faire ce qui lui chante !
Autre exemple, se protéger du cas (improbable... mais l'improbable finit toujours par arriver !) où celui qui lit essaye de le faire en même temps que celui qui écrit. Tu peux utiliser flock (file lock) pour ça. man flock te donnera toutes les infos.
Après tu peux utiliser des solutions plus "complexes" et architecturées. Si par exemple tu as un serveur PhP ou Java, tu peux toujours faire un "WebService" (simplifié) avec une primitive pour 'setter' tes variables, et une pour les 'getter'.
Dernière modification par Zakhar (Le 20/06/2013, à 21:43)
"A computer is like air conditioning: it becomes useless when you open windows." (Linus Torvald)
Hors ligne
#4 Le 20/06/2013, à 22:18
- Zolotaya
Re : [Script] Variable partagée entre plusieurs scripts
Bonsoir,
@amj J'ai déjà essayé avec export et ça ne fonctionne pas. Tu peux essayer en faisant comme ça :
# declare une variable d'environnement
export TEST=test1
# affiche la variable
echo $TEST
# ouverture d'un sous-bash
bash
echo $TEST
# Modification de la variable d'env
TEST=test2
echo $TEST
# affiche test2
exit
# affichage de la variable d'environnement -> test1
echo $TEST
Les variables sont récupérés dans les sous-bachs mais leur portée (en cas de modification) reste dans le bach dans lesquels elles sont modifiés. Dans le cas de mon script, les modifications restes en interne.
@Zakhar
Merci pour cette réponse, c'est intéressant ce que tu dis.
Pour les synalogy je suis OK, mais le faire sois meme permet d'apprendre plus et de pouvoir le faire évoluer comme tu veux. Je peux sans soucis le transformer en pc d'appoint en installant en environnement graphique... Je pense qu'il y a du plus et du moins dans chaque solution
L'idée de l'affichage sur tmpfs ou autre est pas mal mais cela enlève beaucoup de possibilité au script. En gros, tout ce que je peux faire vnstat le fait déjà.
L'idée du script est le suivant : Si on considère le tableau avec m=la minute courante m + 1 la minute précédente ...
[m=10][m+1=0][m+2=3][m+4=50][m+5=100]...
Je peux donc calculer la consommation entre la minute 3 et 5, les 5 dernières minutes... En gros je peux choisir un intervalle de temps pendant laquelle je peux calculer la consommation et pas uniquement les n dernières minutes.
L'idée était de lancer le script un peu comme un daemon et pouvoir l’interroger avec une date de début de recherche et une date de fin (par exemple : "usage d 3 2" me renverrais la bande passante en download entre depuis il y a 3 minutes pour une durée de 2 minutes). Cette appel se ferait depuis un script qui serait appelé par le cron.
Je vais continuer à chercher un peu
Hors ligne
#5 Le 20/06/2013, à 22:39
- pingouinux
Re : [Script] Variable partagée entre plusieurs scripts
Bonsoir,
Au contraire, si le script en cours fait un export, lorsqu'il se termine, le "parent" (ici la console) voit encore la variable.
Un export chez le père permet de passer une variable au processus fils, mais une variable modifiée chez le fils, qu'il fasse un export ou non, ne sera pas modifiée chez le père.
$ cat mon_script
echo "a=$a (début script)"
export a=5
echo "a=$a (fin script)"
$ a=4; echo "a=$a (avant script)"; ./mon_script; echo "a=$a (après script)"
a=4 (avant script)
a= (début script)
a=5 (fin script)
a=4 (après script)
$ export a=3; echo "a=$a (avant script)"; ./mon_script; echo "a=$a (après script)"
a=3 (avant script)
a=3 (début script)
a=5 (fin script)
a=3 (après script)
Hors ligne
#6 Le 20/06/2013, à 22:44
- amj
Re : [Script] Variable partagée entre plusieurs scripts
Je me doutais bien que c'était trop simple
Vive le logiciel libre !! Articles aléatoires sur Wikipédia sur les logiciels libre, sur linux.
Hors ligne
#7 Le 20/06/2013, à 22:57
- Zakhar
Re : [Script] Variable partagée entre plusieurs scripts
Oui c'est sûr, on apprend mieux en faisant son NAS soit-même... "the hard way" comme disent nos amis d'outre-manche... sur ta facture !
Mais il est clair que ça te donne au final une machine plus évolutive qu'un NAS.
Pour ce que tu imagines, tu vois bien que tu es en train de penser :
- il y a un "service" qui mesure la consommation réseau et 'sert' des requêtes 'usage'
- il y a un "client" consommateur du service (le cron) qui demande l'usage et agit en conséquence.
C'est une bonne architecture, mais si tu restes en shell, tu vas être limité par le shell et les outils disponibles.
En effet, ton "service" doit à la fois mesurer la consommation, et "servir" une demande d'usage.
Un script classique étant 'monotâche' ne peut pas faire les deux à la fois.
Pour pouvoir faire les deux à la fois il te faut clairement un truc 'multitâche'.
Ce n'est pas qu'on ne puisse pas faire de shell multitâches... on peut tout à fait lancer un "fils" en tâche de fond et le surveiller, mais de toute façon la communication shell parent/shell fils sera presque aussi compliquée que communiquer avec le cron.
Si ta période de scan est suffisant grande (1min) tu peux faire presque aussi bien que le multitâche.
Tu peux alternativement :
- lire les stats
- utiliser un netcat qui 'écoute' les demandes d'usage
- tu mets un timer sur ton netcat pour boucler sur tes stats
Du côté cron, tu es obligé de faire une petit boucle d'attente pour le cas où tu tombes sur un moment où le netcat n'est pas actif.
En gros ça revient au même que le fichier, sauf qu'au lieu d'écrire systématiquement le fichier, tu l'écris vers le cron quand il te le demande.
Niveau sécurité et failles c'est pas mieux. Un attaquant peut profiter d'un moment où ton script 1 lit pour servir à la place de ton script et balancer des valeurs qui arrêteront ton PC... ou planteront ton script 1 parce que tu as fait un nc sur un port occupé...
Le même attaquant peut aussi lire en permanence sur ce port histoire que les stats aient peu de chance d'arriver au cron.
Bon tests !
"A computer is like air conditioning: it becomes useless when you open windows." (Linus Torvald)
Hors ligne
#8 Le 20/06/2013, à 23:04
- Zakhar
Re : [Script] Variable partagée entre plusieurs scripts
Bonsoir,
Zakhar #3 a écrit :Au contraire, si le script en cours fait un export, lorsqu'il se termine, le "parent" (ici la console) voit encore la variable.
Un export chez le père permet de passer une variable au processus fils, mais une variable modifiée chez le fils, qu'il fasse un export ou non, ne sera pas modifiée chez le père.
Tu as bien fait de corriger, j'ai écrit un peu trop vite le contraire de ce que je voulais dire.
Il n'y a effectivement pas de moyen de passer une variable au père (et encore moins à tout autre process indépendant).
Le seul 'contournement' pour le père est de récupérer le stdout du fils comme ça :
$ ( foo='Hello World'; echo "${foo}" ); echo "${foo}"
Hello World
$ foo="$( foo='Hello World'; echo "${foo}" )"; echo "${foo}"
Hello World
... mais comme de toute façon stdout est un fichier, ça revient à l'écriture en fichier que j'évoquais plus haut.
"A computer is like air conditioning: it becomes useless when you open windows." (Linus Torvald)
Hors ligne