Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Script shell, découper la gestion des options en 2 parties

26 réponses
Avatar
Francois Lafont
Bonsoir à tous,

J'ai écrit toute un série de scripts shell (en l'occurrence c'est du
sh, ie le dash d'une Debian) qui se lancent en ligne de commandes avec
des options --foo --bar etc. Tous les scripts ont une série d'options en
commun et ensuite chacun a en plus des options qui lui sont spécifiques.

Pour la gestion des options en shell, perso j'utilise getopt qui me
va très bien jusque là. Pour un script, j'utilise le schéma classique
que l'on retrouve dans les docs sur getopt, à savoir celui-ci :

-----------------------------------------------------
#!/bin/sh

SCRIPT_NAME=${0##*/}
export LC_ALL=C
export PATH='/usr/sbin:/usr/bin:/sbin:/bin'

print_help () {
cat <<EOF
The syntax is:
$SCRIPT_NAME --common1='<value1>' --common2='<value2>' --foo='<bar>'
EOF
}


options_list='help,common1:,common2:,foo:'

if ! TEMP=$(getopt -o "h" -l "$options_list" -n "$SCRIPT_NAME" -- "$@")
then
echo "Syntax error with $SCRIPT_NAME command." >&2
exit 1
fi

eval set -- "$TEMP"
unset TEMP

while true
do
case "$1" in
--common1)
common1="$2"
shift 2
;;

--common2)
common2="$2"
shift 2
;;

--foo)
foo="$2"
shift 2
;;

--help|-h)
print_help
exit 0
;;

--)
shift 1
break
;;
esac
done

# Et ensuite, j'ai mes variables common1, common2 et foo
# à utiliser dans la suite du script pour que celui-ci
# fasse ce que je veux qu'il fasse...
-----------------------------------------------------

Vous voyez ci-dessus, j'ai deux options --common1 et
--common2 qui sont des options communes à tous mes scripts
et l'option --foo, elle, est spécifique au script. Je simplifie
ici car dans mon cas perso il y a plus que 2 options en commun
et en plus ces options communes nécessitent un petit traitement
a posteriori etc. Bref, autant de code que je suis obligé de
dupliquer d'un script à l'autre. Et dans ce cas, toute modification
au niveau de la gestion des options communes devient pénible à gérer
puisqu'il faut modifier sur chaque script sans se tromper.

Ce que je voudrais, c'est avoir cette arborescence :

mes_scripts/
|-- script1.sh
|-- script2.sh
|
| [etc.]
|
|-- scriptN.sh
`-- share/
`-- common_options.sh

où je factoriserais tout le code en rapport avec les options
communes dans share/common_options.sh et dans chaque script
à la racine je ferais quelque choses comme ça :

-----------------------------------------------------
#!/bin/sh

SCRIPT_NAME=${0##*/}
export LC_ALL=C
export PATH='/usr/sbin:/usr/bin:/sbin:/bin'

# On va sourcer le fichier common_options.sh de sorte
# qu'ensuite on peut bénéficier des variables common1
# et common2 etc.
. ./share/common_options.sh

# Maintenant les variables common1 et common2 sont
# bien définies dans le script.

# Dans la suite du script, on va gérer avec getopt les
# options propres au script et uniquement celles-ci
# (ie l'option --foo dans le cas du script donné en
# exemple ci-dessus).
-----------------------------------------------------

Mon problème est que je n'arrive pas à avoir cela.
Je pensais par exemple faire un getopt dans common_options.sh
qui ne gère que les options communes et un getopt dans chaque
script qui ne gère que les options spécifiques mais ça ne marche
pas car dans common_options.sh le getopt plante car il voit
des options qu'il ne reconnaît pas (forcément puisqu'elles seront
traitées après dans le script appelant). Si getopt avait une option
pour lui dire « les options que tu ne connais pas, mets-les dans un
coin mais ne lève pas d'erreur », je pourrais peut-être m'en sortir
ainsi mais getopt ne possède pas une telle fonctionnalité malheureusement.
Apparemment, quand getopt est appelé il faut lui indiquer toutes
les options, pas seulement un bout, ce qui ne facilite pas le
découpage que je souhaite faire.

Après, peut-être qu'il y a une astuce à laquelle je n'ai pas
pensé. Peut-être une « siouxerie » à base de eval... Je ne sais
pas. En tout cas, je n'ai pour l'instant absolument rien trouvé
qui me permette de factoriser le code au niveau des la gestion
des options communes.

Voilà, j'espère avoir été a peu près clair, si vous avez des idées
je suis preneur. Merci d'avance pour votre aide.

--
François Lafont

10 réponses

1 2 3
Avatar
Francois Lafont
Bonjour,

Le 30/03/2014 09:06, Benoit Izac a écrit :

Désolé mais je ne connais Nagios que de nom, je n'ai jamais pris le
temps de m'y mettre (pas de besoin non plus).



C'est tout à fait normal si tu n'en as pas besoin. Mais Nagios ou
pas (en fait j'utilise shinken qui est un équivalent de Nagios),
peu importe. C'est juste pour indiquer que je suis dans un contexte
où les scripts sont exécutés très fréquemment.

En regardant vite fait,
j'ai trouvé ça (Perl) :
<http://www.pplusdomain.net/Writing%20Nagios%20Plugins%20in%20Perl.pdf>
<http://search.cpan.org/~maxschube/Nagios-Plugin-SNMP-1.2/lib/Nagios/Plugin/SNMP.pm>



Je viens de regarder ce module Perl, il dépend du module Net::SNMP
qui est le module que j'avais utilisé pour faire mes tests en Perl.
Et j'avais une charge CPU plus élevé qu'avec du shell sh.

Si j'ai bien compris un plugin snmp consiste en :
1) faire une requête snmp ou exécuter une commande local



Dans mon cas, cela exécute toujours une requête SNMP vers un hôte
distant.

2) analyser la réponse
3) renvoyer sur la sortie standard : état - informations



Exactement. Sachant que, en plus de la sortie standard, le logiciel
de supervision se base toujours sur le exit code du plugin qui par
convention vaut 0 quand tout est OK, 1 pour indiquer un WARNING, 2
pour indiquer un CRITICAL (ie ça ne va pas et c'est plus grave qu'un
WARNING) et enfin 3 pour indiquer un UNKNOWN (ie il y a eu un souci
lors de l'exécution du plugin et on ne connaît pas l'état du service
à checker).

Et donc au niveau de mes plugins SNMP codés en shell, je dois gérer
des options communes par rapport à l'authentification SNMP (car ce
protocole nécessite une forme d'authentification via des mots de passe,
authentification qui se base sur des éléments différents suivant qu'on
utilise SNMP v2 ou v3). De ce point de vue, il me semble que l'exemple
de code que j'ai donné dans mon message du 29 mars à 16h28 permet de
factoriser la gestion des options communes (tu imagines dans ce code que
--common1 et --common2 correspondent à des options dédiées à l'authentification
SNMP)... avec l'inconvénients que des variables sont entrelacées entre le
fichier script1.sh (qui est le plugin) et le fichier ./share/common_options.sh.

Pour les perf, à quel niveau est-ce que ça coince ?



C'est juste au niveau de la charge CPU où je vois qu'elle augmente
un peu quand je remplace un plugin shell par une version dans un
autre langage. En fait, je ne suis pas amusé à remplacer tous mes
plugins shell en Perl par exemple pour tester ensuite. Je me contente
de prendre un plugin en particulier (assez simple), je le code en
Perl par exemple, puis je le lance en boucle à destination d'une
série d'hôtes. Je fais la même chose avec la version shell du plugin
et je compare le temps d'exécution et la charge CPU. J'ai procédé
ainsi pour shell vs Python et shell vs Perl et c'est shell le
« gagnant ».

--
François Lafont
Avatar
Benoit Izac
Bonjour,

le 30/03/2014 à 15:00, Francois Lafont a écrit dans le message
<53381560$0$2029$ :

Je viens de regarder ce module Perl, il dépend du module Net::SNMP
qui est le module que j'avais utilisé pour faire mes tests en Perl.
Et j'avais une charge CPU plus élevé qu'avec du shell sh.



Ça n'est pas le shell qui compte ici, c'est la commande avec laquelle tu
fais ta requête snmp (snmpget ?). Tu pourrais aussi bien la lancer en
Perl (ou autre chose) si c'est réellement le goulot d'étranglement.

Et donc au niveau de mes plugins SNMP codés en shell, je dois gérer
des options communes par rapport à l'authentification SNMP (car ce
protocole nécessite une forme d'authentification via des mots de passe,
authentification qui se base sur des éléments différents suivant qu'on
utilise SNMP v2 ou v3).



Et la commande que tu utilises n'a pas la possibilité d'utiliser un
fichier de configuration pour obtenir ces informations (snmp.conf(5)) ?

Dans le cas contraire, ce serait plus simple de faire un script qui va
chercher ces informations dans ce que tu veux (fichier(s), base de
données, etc.) et que tu appelles depuis le plugin.

Pour les perf, à quel niveau est-ce que ça coince ?



C'est juste au niveau de la charge CPU où je vois qu'elle augmente
un peu quand je remplace un plugin shell par une version dans un
autre langage. En fait, je ne suis pas amusé à remplacer tous mes
plugins shell en Perl par exemple pour tester ensuite. Je me contente
de prendre un plugin en particulier (assez simple), je le code en
Perl par exemple, puis je le lance en boucle à destination d'une
série d'hôtes. Je fais la même chose avec la version shell du plugin
et je compare le temps d'exécution et la charge CPU. J'ai procédé
ainsi pour shell vs Python et shell vs Perl et c'est shell le
« gagnant ».



Donc la commande écrite en C (ou C++). Aurais-tu, par hasard, des
chiffres pour me permettre de savoir ce que tu quantifies comme
« un peu » ? Il serait également intéressant de voir les scripts.

--
Benoit Izac
Avatar
Francois Lafont
Bonsoir,

Le 30/03/2014 16:29, Benoit Izac a écrit :

Je viens de regarder ce module Perl, il dépend du module Net::SNMP
qui est le module que j'avais utilisé pour faire mes tests en Perl.
Et j'avais une charge CPU plus élevé qu'avec du shell sh.



Ça n'est pas le shell qui compte ici, c'est la commande avec laquelle tu
fais ta requête snmp (snmpget ?).



Oui, en général c'est un snmpget et dans mes tests, j'ai pris
snmpget, aussi bien en shell qu'en perl.

Tu pourrais aussi bien la lancer en
Perl (ou autre chose) si c'est réellement le goulot d'étranglement.



Ah, c'est intéressant. Donc, si je te suis bien, au final la
vraie raison du ralentissement constaté de perl par rapport
au shell pourrait être au final confiné au niveau du snmpget
et le reste serait en fait négligeable (ie du grep ou du sed
par-ci par-là en shell ou bien des regex etc. en perl au final
ça serait kif-kif) ?

Ça veut dire que si je vire toute la partie SNMP d'un plugin
en perl pour y faire un appel système de la commande snmpget
alors j'aurai des perf à peu près identique entre un plugin
perl et son équivalent en shell ?

Je ne sais pas faire un appel à une commande en perl tout en
récupérant la sortie ainsi que le exit code (je suis un débutant
en Perl), mais il faudra que je regarde ça.

Et donc au niveau de mes plugins SNMP codés en shell, je dois gérer
des options communes par rapport à l'authentification SNMP (car ce
protocole nécessite une forme d'authentification via des mots de passe,
authentification qui se base sur des éléments différents suivant qu'on
utilise SNMP v2 ou v3).



Et la commande que tu utilises n'a pas la possibilité d'utiliser un
fichier de configuration pour obtenir ces informations (snmp.conf(5)) ?



Si mais c'est exclu pour moi. Je m'explique. C'est le logiciel
de supervision qui lance les plugins avec les bons arguments etc.
Et en l'occurrence c'est dans la conf du logiciel de supervision
que sont stockés les divers mots de passe SNMP des hôtes. Et d'un
hôte à un autre, ça peut changer. Par exemple, certains hôtes ne
« parlent » même pas le SNMP v3 mais seulement le v2, deux hôtes
en SNMP v3 n'ont pas forcément les mêmes mots de passe (même si
c'est souvent le cas, ce n'est pas systématique) etc. Bref, le
logiciel voit tout ça dans *sa* conf à lui et en fonction de cela,
il lancera les plugins avec les bons arguments (ie les bons mots de
passe SNMP entre autres). Je ne peux pas et ne dois pas sortir de ce
schéma là.

C'est juste au niveau de la charge CPU où je vois qu'elle augmente
un peu quand je remplace un plugin shell par une version dans un
autre langage. En fait, je ne suis pas amusé à remplacer tous mes
plugins shell en Perl par exemple pour tester ensuite. Je me contente
de prendre un plugin en particulier (assez simple), je le code en
Perl par exemple, puis je le lance en boucle à destination d'une
série d'hôtes. Je fais la même chose avec la version shell du plugin
et je compare le temps d'exécution et la charge CPU. J'ai procédé
ainsi pour shell vs Python et shell vs Perl et c'est shell le
« gagnant ».



Donc la commande écrite en C (ou C++).



En l'occurrence, je crois bien que net-snmp (l'implémentation sous
Linux de SNMP partie serveur et client) est codé en C. Donc, d'après
toi, c'est là où le shell « l'emporterait » ? Ce qui voudrait donc
dire en effet que ce n'est pas le shell en lui-même qui l'emporterait
mais le fait qu'il fasse appel à une implémentation de SNMP client
plus performante que l'implémentation SNMP utilisée par Perl ? Le
reste selon toi serait négligeable ?

Aurais-tu, par hasard, des
chiffres pour me permettre de savoir ce que tu quantifies comme
« un peu » ? Il serait également intéressant de voir les scripts.



Pas de souci. Voici tout ça :

http://sisco.laf.free.fr/divers/perl-vs-sh.tar.gz

Tu as un check qui va demander l'uptime d'une machine via SNMP
et si celui-ci est inférieur en minutes à un seuil donné en
option du plugin (--warning), alors le plugin retourne un warning
(autrement si l'uptime est < N minutes alors warning car ça veut
dire que l'hôte à probablement rebooté).

1. Tu verras dans le plugin en shell une partie du code est dédiée
à la gestion des options dont la majeure partie (celle dédiée
à l'authentification SNMP) se retrouve dans chaque nouveau plugin
que j'écris en shell et donc grosse répétition de code à chaque
fois. C'était vraiment ça l'objet de mon post à la base.
Attention pour que le plugin shell fonctionne il faut que la
partie cliente de SNMP soit installée sur le système. Par
exemple sous Debian Wheezy :

apt-get install snmp

2. Ensuite tu as le plugin équivalent (à peu près) en perl.
Celui-là, j'ai voulu le couper en deux avec une partie
du code qui se trouve dans "share/snmp.pm". Cette partie
a pour but justement de prendre en charge les options
communes des plugins perl. En effet, passer en perl n'a
d'intérêt pour moi que si j'ai la possibilité de factoriser
la gestion des options communes (authentification SNMP)
dans un unique fichier, chose que je n'arrive pas à faire
proprement en shell.

Bon, autant le dire tout de suite, je suis nul en Perl. Je
n'avais jamais rien codé en Perl il y a encore 1 semaine. Donc
il est tout à fait probable que le script perl soit à revoir.
Ceci étant, je ne pense pas que mes maladresses puissent être
la raison de l'écart que j'ai constaté entre le perl et le shell.
À voir...

Attention pour fonctionner, le plugin en perl à besoin d'une
série de lib. Sous Debian Wheezy, il faut faire :

apt-get install libnet-snmp-perl libcrypt-des-perl
libdigest-hmac-perl libcrypt-rijndael-perl

3. Et puis tu as le script bench.sh qui m'a permis de tester
d'abord le plugin shell sur 54 machines d'affilée puis ensuite
le plugin perl sur les mêmes 54 machines. En fait, ce n'est pas
obligé que ce soit 54 machines différentes, ça peut parfaitement
être N fois d'affilée localhost qui est interrogé (ce que j'ai mis
dans le fichier bench.sh du lien ci-dessus). Si jamais tu veux tester
par toi-même tout ça, la configuration de SNMP côté serveur (afin qu'il
réponde aux requêtes SNMP qu'on lui envoie) est très simple. Sous
Debian Wheezy, ça donne :

-----------------------------------------------
apt-get install snmpd # SNMP partie serveur

cat > /etc/snmp/snmpd.conf <<EOF
agentAddress udp:161
agentSecName toto12
# Le login toto12 pour faire des requêtes SNMP.
createUser toto12 SHA 1234567890AZERTY AES ABCDEF1234567890ABCDE
view monitoring included .1.3.6.1.2.1
view monitoring included .1.3.6.1.4.1
rouser toto12 priv -V monitoring
dontLogTCPWrappersConnects yes
disablePerl true
skipNFSInHostResources true
storageUseNFS 1
master agentx
EOF

invoke-rc.d snmpd restart # et c'est prêt.
-----------------------------------------------

Dans mon cas, voici ce que donne le bench. Pour le shell :

~# time ./bench.sh shell

real 0m2.494s
user 0m1.416s
sys 0m0.168s

Et j'ai un CPU qui monte en général aux alentours de 68%.

Pour le perl :

~# time ./bench.sh perl

real 0m5.992s
user 0m4.792s
sys 0m0.920s

Et j'ai un CPU qui monte en général aux alentours de 88%.

Ne serait-ce que visuellement, on voit bien que ça défile
nettement plus vite en shell qu'en perl. Bien sûr, pour chaque
requête SNMP il y a un petit temps de latence au niveau de
la réponse mais c'est le même dans les 2 cas.

Voilà. Merci bien pour ton aide.

--
François Lafont
Avatar
Benoit Izac
Bonjour,

le 31/03/2014 à 04:36, Francois Lafont a écrit dans le message
<5338d4c3$0$2293$ :

Ça veut dire que si je vire toute la partie SNMP d'un plugin
en perl pour y faire un appel système de la commande snmpget
alors j'aurai des perf à peu près identique entre un plugin
perl et son équivalent en shell ?



Oui.

Je ne sais pas faire un appel à une commande en perl tout en
récupérant la sortie ainsi que le exit code (je suis un débutant
en Perl), mais il faudra que je regarde ça.



<http://articles.mongueurs.net/magazines/linuxmag55.html>

Et la commande que tu utilises n'a pas la possibilité d'utiliser un
fichier de configuration pour obtenir ces informations (snmp.conf(5)) ?



Si mais c'est exclu pour moi. Je m'explique. C'est le logiciel
de supervision qui lance les plugins avec les bons arguments etc.
Et en l'occurrence c'est dans la conf du logiciel de supervision
que sont stockés les divers mots de passe SNMP des hôtes. Et d'un
hôte à un autre, ça peut changer. Par exemple, certains hôtes ne
« parlent » même pas le SNMP v3 mais seulement le v2, deux hôtes
en SNMP v3 n'ont pas forcément les mêmes mots de passe (même si
c'est souvent le cas, ce n'est pas systématique) etc. Bref, le
logiciel voit tout ça dans *sa* conf à lui et en fonction de cela,
il lancera les plugins avec les bons arguments (ie les bons mots de
passe SNMP entre autres). Je ne peux pas et ne dois pas sortir de ce
schéma là.



C'est bien là le problème à mon avis. Et je pense qu'utiliser des
variables d'environnement est la méthode la plus simple pour séparer les
arguments que tu dois passer au script et l'authentification aux
machines.

En l'occurrence, je crois bien que net-snmp (l'implémentation sous
Linux de SNMP partie serveur et client) est codé en C. Donc, d'après
toi, c'est là où le shell « l'emporterait » ? Ce qui voudrait donc
dire en effet que ce n'est pas le shell en lui-même qui l'emporterait
mais le fait qu'il fasse appel à une implémentation de SNMP client
plus performante que l'implémentation SNMP utilisée par Perl ? Le
reste selon toi serait négligeable ?



Testons !

Issue de perldoc Net::SNMP :
=========================================================================== #!/usr/bin/perl
use strict;
use warnings;
use Net::SNMP;
my $OID_sysUpTime = '1.3.6.1.2.1.1.3.0';
my ($session, $error) = Net::SNMP->session(
-hostname => shift || 'localhost',
-community => shift || 'public',
);
if (!defined $session) {
printf "ERROR: %s.n", $error;
exit 1;
}
my $result = $session->get_request(-varbindlist => [ $OID_sysUpTime ],);
if (!defined $result) {
printf "ERROR: %s.n", $session->error();
exit 1;
}
printf "The sysUpTime for host '%s' is %s.n",
$session->hostname(), $result->{$OID_sysUpTime};
$session->close();
exit 0;
===========================================================================
(oak c'est mon imprimante)
% time sh -c 'for f in {1..1000}; do
snmpget -v 2c -c public oak 1.3.6.1.2.1.1.3.0
done >/dev/null'
10.80s user 1.45s system 61% cpu 20.037 total

% time sh -c 'for f in {1..1000}; do
perl ~/tmp/perl_snmp.pl oak
done >/dev/null'
62.49s user 4.99s system 89% cpu 1:15.33 total

Il n'y a pas photo, snmpget est 3,7 fois plus rapide que son équivalent
en Perl. Mais bon, Perl ne te sert pas à grand chose puisque tu ne
profites pas de Nagios::Plugin dont parlait le document que j'ai t'ai
indiqué précédemment. Notamment les « $np->add_arg() » qui devraient te
permettre de faire une fonction qui prendrait en argument ton objet
Nagios::Plugin et lui rajouterait toutes les options qui sont communes
à tous les scripts.

Note que l'option pass_through de Getopt::Long devrait te plaire
également.

--
Benoit Izac
Avatar
Francois Lafont
Bonsoir,

Déjà, merci encore pour ton aide Benoît.

Le 31/03/2014 22:25, Benoit Izac a écrit :

Et la commande que tu utilises n'a pas la possibilité d'utiliser un
fichier de configuration pour obtenir ces informations (snmp.conf(5)) ?



Si mais c'est exclu pour moi. Je m'explique. C'est le logiciel
de supervision qui lance les plugins avec les bons arguments etc.
Et en l'occurrence c'est dans la conf du logiciel de supervision
que sont stockés les divers mots de passe SNMP des hôtes. Et d'un
hôte à un autre, ça peut changer. Par exemple, certains hôtes ne
« parlent » même pas le SNMP v3 mais seulement le v2, deux hôtes
en SNMP v3 n'ont pas forcément les mêmes mots de passe (même si
c'est souvent le cas, ce n'est pas systématique) etc. Bref, le
logiciel voit tout ça dans *sa* conf à lui et en fonction de cela,
il lancera les plugins avec les bons arguments (ie les bons mots de
passe SNMP entre autres). Je ne peux pas et ne dois pas sortir de ce
schéma là.



C'est bien là le problème à mon avis. Et je pense qu'utiliser des
variables d'environnement est la méthode la plus simple pour séparer les
arguments que tu dois passer au script et l'authentification aux
machines.



Sans doute, mais par rapport au logiciel de supervision, je ne pense
pas que ça possible proprement et ni même souhaitable même si dans
l'absolu je suis d'accord avec toi. De plus, le logiciel de supervision
appelle mes checks maison mais aussi (et heureusement) des checks
tout faits issus du gestionnaire de paquets. Et ces checks (plugins)
ne passent pas par des variables d'environnement pour l'authentification
snmp mais par des options. Du coup, je préfère me caler sur l'existant.

Il n'y a pas photo, snmpget est 3,7 fois plus rapide que son équivalent
en Perl.



Oui, y'a pas photo comme tu dis.

Mais bon, Perl ne te sert pas à grand chose puisque tu ne
profites pas de Nagios::Plugin dont parlait le document que j'ai t'ai
indiqué précédemment. Notamment les « $np->add_arg() » qui devraient te
permettre de faire une fonction qui prendrait en argument ton objet
Nagios::Plugin et lui rajouterait toutes les options qui sont communes
à tous les scripts.



Mais Perl m'intéresse quand même, même en faisant un appel à snmpget
car avec ce langage je peux utiliser des structures de données d'un peu
plus haut niveau que dans du shell sh, comme par exemple les tableaux ou
les dictionnaires. En effet, dans le shell sh, des fois c'est un peu galère
de ne pas disposer de telles structures. Une fois le snmpget effectué, j'ai
besoin d'analyser les données obtenues, de découper des chaînes, de faire
des comparaisons etc. etc. et tout cela en shell est parfois un peu lourd
(à base de echo par-ci, sed par-là). En Perl, tout ce travail pourrait
être plus facile à coder.

Note que l'option pass_through de Getopt::Long devrait te plaire
également.



Mais je l'avais noté puisque je l'utilise dans le script Perl que
j'avais mis en lien dans mon message précédent. C'est typiquement
la fonctionnalité qui me manque avec la commande getopt dans le shell
pour séparer la gestion des options communes du reste des autres options.
Et donc avec Perl j'arrive à faire cette séparation grâce à ce
pass_through qui tombe à pic (cf le lien du message précédent).

À ce stade du coup je me dis qu'avec du Perl + un appel à snmpget
directement (plutôt que d'utiliser une lib Perl pour snmp), je peux
obtenir à la fois une gestion séparée des options et en même temps
des perfs correctes avec en plus la possibilité d'utiliser des
structure de données assez commodes que je n'ai pas en shell sh.
Seulement malgré le fait d'utiliser snmpget, j'ai bien l'impression
que le shell sh reste encore bien devant au niveau perf par rapport
au Perl. Mais... hélas je n'y gagnerai pas sur tous les tableaux...

En effet, dès que possible, je poste ici un petit comparatif car le
peu que j'ai testé jusqu'ici semble m'indiquer que, même en passant
par un appel à snmpget en Perl, le sh reste encore plus rapide que le
Perl et ce de manière non négligeable dans mon contexte (même si
le snmpget réduit pas mal l'écart). À voir...

À bientôt.

--
François Lafont
Avatar
Benoit Izac
Bonjour,

le 02/04/2014 à 01:27, Francois Lafont a écrit dans le message
<533b4b7a$0$2287$ :

Note que l'option pass_through de Getopt::Long devrait te plaire
également.



Mais je l'avais noté puisque je l'utilise dans le script Perl que
j'avais mis en lien dans mon message précédent. C'est typiquement
la fonctionnalité qui me manque avec la commande getopt dans le shell
pour séparer la gestion des options communes du reste des autres options.
Et donc avec Perl j'arrive à faire cette séparation grâce à ce
pass_through qui tombe à pic (cf le lien du message précédent).



Aïe, ça s'est vu que j'ai regardé ton code plus qu'en diagonale. ;-)

On attend les stats mais il est certain que tous les appels vers des
commandes native du système seront toujours plus rapide que l'équivalent
en Perl. Après, le tout est de savoir si c'est acceptable (et
généralement ça l'est).

--
Benoit Izac
Avatar
Nicolas George
Benoit Izac , dans le message , a écrit :
On attend les stats mais il est certain que tous les appels vers des
commandes native du système seront toujours plus rapide que l'équivalent
en Perl.



Euh, gnî ? Tu peux justifier ce que affirmes là, s'il te plaît ?
Avatar
Benoit Izac
Bonjour,

le 02/04/2014 à 11:57, Nicolas George a écrit dans le message
<533bdefc$0$2126$ :

On attend les stats mais il est certain que tous les appels vers des
commandes native du système seront toujours plus rapide que l'équivalent
en Perl.



Euh, gnî ? Tu peux justifier ce que affirmes là, s'il te plaît ?



Ce qui est évoqué précédemment : le snmpget codé en C est plus rapide
que l'équivalent en Perl. Ce que j'entends par commande native : un
programme qui est compilé pour la machine que l'on utilise,
contrairement à Perl qui est portable, c'est à dire que le même
programme fonctionne sur d'autres architectures sans avoir à recompiler.

Après, je suis certain que tu trouveras des contre-exemples ; j'ai déjà
entendu dire que le File::Find de Perl pourrait être plus rapide que le
find "natif" (gnu find par exemple) mais d'une manière générale ce n'est
pas le cas.

Maintenant, je ne dis pas qu'il faille remplacer le code Perl par des
appels à des commandes natives, je dis juste qu'au niveau des
performances, on sera toujours (ou presque) en dessous. Et je ne parle
pas du shell (qui n'est qu'un chef d'orchestre) mais bien de commandes
(snmpget, find, etc.).

--
Benoit Izac
Avatar
Nicolas George
Benoit Izac , dans le message , a écrit :
Ce qui est évoqué précédemment : le snmpget codé en C est plus rapide
que l'équivalent en Perl.



C'est faux. Le boulot de snmpget se limite à formater une requête réseau,
recevoir la réponse et afficher le résultat. La majeure partie du temps est
passée dans des appels système, le travail effectivement fait par le
programme, et où peut se manifester la différence entre code compilé et
interprété, est négligeable.

Ce qui n'est pas négligeable, en revanche, c'est le surcroît de travail lié
à une commande externe : recherche du binaire dans les chemins, lancement
d'un nouveau processus, édition de liens dynamique. Tout ça n'arrive qu'au
début avec du code en perl, alors que c'est refait à chaque appel avec une
commande externe. Plus, dans le cas présent, les requêtes DNS, dont le
résultat peut être caché dans le cas de perl.

Si tu veux t'en convaincre, tu peux vérifier sur un cas plus simple, par
exemple renommer dix mille fichiers pour ajouter un préfixe au nom :

shell : for i in *; do mv $i p-$i; done
perl : perl -e 'for my $i (glob "*") { rename $i, "p-$i" }'

Il n'y a pas photo : chez moi, perl se termine en moins de 0,37 seconde
alors que le shell met presque 7 secondes.
Avatar
Francois Lafont
Bonjour,

Le 02/04/2014 14:12, Nicolas George a écrit :

C'est faux. Le boulot de snmpget se limite à formater une requête réseau,
recevoir la réponse et afficher le résultat. La majeure partie du temps est
passée dans des appels système, le travail effectivement fait par le
programme, et où peut se manifester la différence entre code compilé et
interprété, est négligeable.

Ce qui n'est pas négligeable, en revanche, c'est le surcroît de travail lié
à une commande externe : recherche du binaire dans les chemins, lancement
d'un nouveau processus, édition de liens dynamique. Tout ça n'arrive qu'au
début avec du code en perl, alors que c'est refait à chaque appel avec une
commande externe. Plus, dans le cas présent, les requêtes DNS, dont le
résultat peut être caché dans le cas de perl.

Si tu veux t'en convaincre, tu peux vérifier sur un cas plus simple, par
exemple renommer dix mille fichiers pour ajouter un préfixe au nom :

shell : for i in *; do mv $i p-$i; done
perl : perl -e 'for my $i (glob "*") { rename $i, "p-$i" }'

Il n'y a pas photo : chez moi, perl se termine en moins de 0,37 seconde
alors que le shell met presque 7 secondes.



Si j'ai bien suivi, tu penches plutôt pour de meilleures perfs
avec du Perl qu'avec du Shell. Mais dans ce cas comment expliquer
le fait que Benoît et moi-même constatons des temps d'exécution
relativement plus rapide en Shell qu'en Perl (pour des scripts
à peu près équivalents) ?

Voir par exemple mes tests ici :

http://sisco.laf.free.fr/divers/perl-vs-sh.tar.gz

où dans mon message du 31mars à 4h36, j'expliquais que j'avais
une exécution environ 2 fois plus rapide en shell qu'en Perl.
Il y a aussi les tests de Benoît dans son message du 31 à 22h25.

En te relisant, j'ai l'impression que tu penses que ça devrait
être l'inverse.


--
François Lafont
1 2 3