Auteur Sujet: bash: verifier les arguments passés à un script  (Lu 4325 fois)

0 Membres et 1 Invité sur ce sujet

vivien

  • Administrateur
  • *
  • Messages: 47 213
    • Twitter LaFibre.info
bash: verifier les arguments passés à un script
« le: 27 janvier 2022 à 19:57:31 »
Je me demande si il y a une solution propre et simple pour vérifier les arguments passés lors de l'appel d'un script bash.

Voici un exemple simple, avec un script qui télécharge un fichier à un débit indiqué en argument (c'est pour mesurer la consommation des box avec un trafic). Le second argument (protocole IP) est lui aussi obligatoire.

Je souhaites que si on lance le script sans argument ou avec un seul argument il affiche l'aide indiquant la syntaxe du script.

Si je fais les deux tests (présence de 2 arguments et vérifier que l'argument est entre 100 et 1000000) avant d'afficher le message, en absence d’argument j'ai un message d'erreur de bash, car le second test se fait alors que l'argument n'est pas initialisé "./gen-trafic.sh: ligne 38 : [: trop d'arguments"

Voici la solution que j'ai trouvé, mais dupliquer le message d'aide ne me semble pas top :


#!/bin/bash
# gen-trafic.sh : Script pour simuler un trafic https avec un débit moyen indiqué en argument
# dépendance : wget (déjà pré-installée avec Ubuntu)
# Version du 27 janvier 2022 créé par Vivien Guéant

# Initialisation des variables
URL=https://ubuntu.lafibre.info/10G.iso
DEBIT=""
PROTOCOLE=""

# Vérification de la présence des arguments passés en paramètres
case ${2in
  
-4)
    
PROTOCOLE="-4 "
    
;;
  -
6)
    
PROTOCOLE="-6 "
    
;;
  -
64)
    ;;
  *)
    echo -
"Syntaxe incorrecte : deux arguments sont nécessaires.\n"
    
echo -"Utilisation : ./gen-trafic DEBIT PROTOCOLE\n"
    
echo -"DEBIT : débit souhaité, exprimé en Kilobit par seconde"
    
echo -"        minimum \"100\" pour 100 Kbit/s"
    
echo -"        maximum \"1000000\" pour 1 Gbit/s\n"
    
echo -"PROTOCOLE : choix du protocole réseau"
    
echo -"        \"-4\" pour forcer le transfert en IPv4"
    
echo -"        \"-6\" pour forcer le transfert en IPv6"
    
echo -"        \"-64\" pour privilégier IPv6 si disponible, sinon IPv4\n"
    
echo -"EXEMPLE pour simuler un trafic de 2,5 Mb/s en IPv6: \"./gen-trafic.sh 2500 -6\""
    
exit 1
    
;;
esac

# Calcul de débit en octets par seconde
if [ ${1} -ge 100 -${1} -le 1000000 ];
then
   DEBIT
=$((${1} * 125))
else
    echo -
"Syntaxe incorrecte : le débit doit être compris entre \"100\" et \"1000000\".\n"
    
echo -"Utilisation : ./gen-trafic DEBIT PROTOCOLE\n"
    
echo -"DEBIT : débit souhaité, exprimé en Kilobit par seconde"
    
echo -"        minimum \"100\" pour 100 Kbit/s"
    
echo -"        maximum \"1000000\" pour 1 Gbit/s\n"
    
echo -"PROTOCOLE : choix du protocole réseau"
    
echo -"        \"-4\" pour forcer le transfert en IPv4"
    
echo -"        \"-6\" pour forcer le transfert en IPv6"
    
echo -"        \"-64\" pour privilégier IPv6 si disponible, sinon IPv4\n"
    
echo -"EXEMPLE pour simuler un trafic de 2,5 Mb/s en IPv6: \"./gen-trafic.sh 2500 -6\""
    
exit 1
fi

# Lancement de wget
echo -"Génération d un trafic https de ${1} Kbit/s (soit ${DEBIT} octets par seconde).\n"
while [ ]
do
    
wget ${PROTOCOLE}--limit-rate=${DEBIT} -/dev/null ${URL}
done

vivien

  • Administrateur
  • *
  • Messages: 47 213
    • Twitter LaFibre.info
bash: verifier les arguments passés à un script
« Réponse #1 le: 27 janvier 2022 à 22:00:56 »
Au passage, j'ai testé curl avec un "--limit-rate" : cela fonctionne bien que pour des débits très élevés ( > 100 Mb/s) : car il va lancer le téléchargement pour une taille importante avant de s’arrêter plusieurs secondes si on lui demande un petit débit.

wget est sur ce point bien mieux que curl

J'ai aussi testé wget2 qui est conçu et réécrit à partir de zéro et intègre de nouvelles fonctionnalités comme HTTP/2 (déjà pris en charge par curl), mais aussi des retraits, comme la fin de la prise en charge de FTP et du format WARC (fichier d'archive combinant plusieurs ressources numériques). Le "--limit-rate" ne semble pas encore fonctionner avec wget2.

MoXxXoM

  • Abonné Starlink
  • *
  • Messages: 957
bash: verifier les arguments passés à un script
« Réponse #2 le: 27 janvier 2022 à 22:24:07 »
Je me demande si il y a une solution propre et simple pour vérifier les arguments passés lors de l'appel d'un script bash.

Tu peux utiliser la primitive bash getopts et/ou l'outil getopt (https://manpages.debian.org/testing/util-linux/getopt.1.en.html) pour valider/parser les options.

Zweit

  • Abonné Free fibre
  • *
  • Messages: 238
  • Bieville-Beuville (14)
bash: verifier les arguments passés à un script
« Réponse #3 le: 28 janvier 2022 à 06:54:33 »
Salut,

Je suis loin d'être expert en bash, mais pourquoi ne pas, au lieu de dupliquer le message, le mettre dans une fonction ?

Et si tu as plusieurs messages, tu peux passer un argument dans cette fonction pour choisir le message à afficher.

eupalynos

  • Abonné Free vdsl
  • *
  • Messages: 47
  • Thônes (74)
bash: verifier les arguments passés à un script
« Réponse #4 le: 28 janvier 2022 à 10:49:39 »
Bonjour,

Je te propose :
#!/bin/bash

show_help() {
cat << EOF
Usage: ${0##*/} [-h|-4|-6] [rate]

Simulate HTTPS traffic with throughput 'rate' in bit/s (default 100 kbit/s). The rate can be suffixed with the multipliers "K", "M" or "G" (not case sensitive), respectively for kilo, mega or giga. Example : 100k = 100 kbit/s. Minimum rate is 100 kbit/s, maximum rate is 1 Gbit/s.
By default it uses the IPv6 protocol if available, otherwise IPv4.

OPTIONS:
  -h          display this help and exit (ignore other options or parameters)
  -4          force IPv4 protocol
  -6          force IPv6 protocol
EOF
}

val=100
unit=k
protocol=

min=$((100*1000))
max=$((1*1000*1000*1000))

OPTIND=1
while getopts h46 opt; do
    case $opt in
h) show_help ; exit 0 ;;
4) protocol=4 ;;
6) protocol=6 ;;
*) printf 'Unknown option: %s\n' "$1" >&2 ; exit 1 ;;
    esac
done
shift "$((OPTIND-1))"

arg="$@"
if [ -n "$arg" ] ; then
regex="^([1-9][0-9]*)(k|K|m|M|g|G)?$"
if [[ $arg =~ $regex ]] ; then
val=${BASH_REMATCH[1]}
unit=${BASH_REMATCH[2]}
    else
echo "Rate '$arg' is invalid" >&2
exit 1
fi
fi

case $unit in
k|K) mult=1000 ;;
m|M) mult=$((1000*1000)) ;;
g|G) mult=$((1000*1000*1000)) ;;
*) mult=1 ;;
esac

rate=$((val*mult))

if (( rate < min )) || (( rate > max )); then
echo "Rate '$arg' is out of bounds" >&2
exit 1
fi

# From here we can use the verified parameters

echo -n "protocol : "
if [ -z $protocol ] ; then
echo "IPv6 if availabale, otherwise IPv4"
else
echo "IPv$protocol"
fi
echo "rate : $rate bit/s"

exit 0

A+

vivien

  • Administrateur
  • *
  • Messages: 47 213
    • Twitter LaFibre.info
bash: verifier les arguments passés à un script
« Réponse #5 le: 28 janvier 2022 à 13:02:02 »
Merci eupalynos de m'avoir mâché tout le travail. C'est exactement ce que je cherchais. Avec ton accord, je vais le mettre sur le site de l'Arcep et te mentionnant en co-auteur en haut du bash.

J'ai mis le bash en Français, car si j'ai fais un script pour simplement lancer un simple wget, c'est dans l'objectif de limiter les erreurs, wget prenant les données en multiple de 1024 (Mio/s) alors que le protocole est indique des débits en Mbit/s.

Le premier "Protocole de mesure de la consommation électrique des box" que j'ai écrit multipliait les risques d'erreurs (plusieurs PC avec des interfaces Ethernet différentes, plusieurs longueur de câbles pour connecter le PC à la box [un câble long peut forcer la box à émettre plus et donc à consommer plus] le tout mixé avec du trafic généré en IPv4, IPv6 [certaines vieux chips peuvent consommer plus en IPv6],...). Pour fiabiliser les données et limiter les risques d'erreur involontaires, j'ai rendu le protocole plus logique (ex: Un PC est toujours connecté à la box avec la même longueur de câble) et ce script s'inscrit dans cet objectif limiter les risques d'erreurs involontaires, les débits dans le protocole étant exprimés en kbit/s ou Mbit/s et non en Kio/s ou Mio/s.

J'ai supprimé le "printf 'Unknown option: %s\n' "$1" >&2" dans le premier case, car getopts affiche le message "option non permise -- 5" en cas d'erreur.

J'ai affiché la fonction "show_help" à chaque message d'erreur, car la personne qui va l'utiliser n'aura pas forcément l'idée de faire -h.

Ma proposition :
#!/bin/bash
# Script pour simuler un trafic https avec un débit moyen indiqué en argument
# dépendance : wget (déjà pré-installée avec Ubuntu)
# Version du 28 janvier 2022 créé par Vivien Guéant et eupalynos
# Ce script est un logiciel libre que vous pouvez redistribuer ou modifier suivant la GNU GPLv3

show_help() {
cat << EOF
Utilisation: ${0##*/} [-h|-4|-6] [débit]

Simule un trafic HTTPS avec un "débit" en bit/s (100 Kbit/s par défaut). Le débit, un nombre entier, peut être suffixé par les multiplicateurs "K", "M" ou "G" (non sensible à la casse), respectivement pour Kbit/s, Mbit/s ou Gbit/s. Exemple : 1M = 1 Mbit/s. Le débit minimum est de 100 kbit/s, le débit maximum est de 1 Gbit/s.
Par défaut, le protocole IPv6 est utilisé si disponible, sinon IPv4.

OPTIONS :
   -h affiche cette aide et quitte (ignore les autres options ou paramètres)
   -4 forcer le protocole IPv4
   -6 forcer le protocole IPv6
EOF
}

# Initialisation des variables
url="https://ubuntu.lafibre.info/10G.iso"
val=100
unit=k
protocol=
min=$((100*1000))
max=$((1*1000*1000*1000))

# Vérification de la validité des arguments passés en paramètres
OPTIND=1
while getopts h46 opt; do
case $opt in
h) show_help ; exit 0 ;;
4) protocol="-4 " ;;
6) protocol="-6 " ;;
*) show_help ; exit 1 ;;
esac
done
shift "$((OPTIND-1))"

arg="$@"
if [ -n "$arg" ] ; then
regex="^([1-9][0-9]*)(k|K|m|M|g|G)?$"
if [[ $arg =~ $regex ]] ; then
val=${BASH_REMATCH[1]}
unit=${BASH_REMATCH[2]}
else
printf "Le débit '$arg' est invalide\n\n" >&2
show_help ; exit 1
fi
fi

case $unit in
k|K) mult=1000 ;;
m|M) mult=$((1000*1000)) ;;
g|G) mult=$((1000*1000*1000)) ;;
*) mult=1 ;;
esac

rate=$((val*mult))

if (( rate < min )) || (( rate > max )); then
printf "Le débit '$arg' est hors des limites (minimum de 100 kbit/s, maximum de 1 Gbit/s)\n\n" >&2
show_help ; exit 1
fi

# Calcul de débit en kbit/s et en octets par seconde
ratekb=$((rate / 1000))
ratebyte=$((rate / 8))

# Lancement de wget (boucle infinie)
printf "Simulation d'un trafic https de $ratekb kbit/s (soit $ratebyte octets par seconde).\n"
printf "Ctrl+C pour arrêter le transfert: maintenir la touche \"Ctrl\" enfoncée et appuyer sur la touche \"C\"\n\n"

while [ 1 ]
do
wget $protocol--limit-rate=$ratebyte -O /dev/null ${url}
done
exit 0

eupalynos

  • Abonné Free vdsl
  • *
  • Messages: 47
  • Thônes (74)
bash: verifier les arguments passés à un script
« Réponse #6 le: 28 janvier 2022 à 13:45:00 »
Merci eupalynos de m'avoir mâché tout le travail. C'est exactement ce que je cherchais. Avec ton accord, je vais le mettre sur le site de l'Arcep et te mentionnant en co-auteur en haut du bash.
Pas de problème. Inutile de me mentionner comme co-auteur, je verse ça dans le domaine public.

J'ai mis le bash en Français, car si j'ai fais un script pour simplement lancer un simple wget, c'est dans l'objectif de limiter les erreurs, wget prenant les données en multiple de 1024 (Mio/s) alors que le protocole est indique des débits en Mbit/s.
J'ai l'habitude de mettre les messages en anglais, désolé...

Le premier "Protocole de mesure de la consommation électrique des box" que j'ai écrit multipliait les risques d'erreurs (plusieurs PC avec des interfaces Ethernet différentes, plusieurs longueur de câbles pour connecter le PC à la box [un câble long peut forcer la box à émettre plus et donc à consommer plus] le tout mixé avec du trafic généré en IPv4, IPv6 [certaines vieux chips peuvent consommer plus en IPv6],...). Pour fiabiliser les données et limiter les risques d'erreur involontaires, j'ai rendu le protocole plus logique (ex: Un PC est toujours connecté à la box avec la même longueur de câble) et ce script s'inscrit dans cet objectif limiter les risques d'erreurs involontaires, les débits dans le protocole étant exprimés en kbit/s ou Mbit/s et non en Kio/s ou Mio/s.

J'ai supprimé le "printf 'Unknown option: %s\n' "$1" >&2" dans le premier case, car getopts affiche le message "option non permise -- 5" en cas d'erreur.
Ah oui, j'ai oublié ":" avant la liste de options.
Donc, c'est ça :
while getopts :h46 opt; do
au lieu de ça :
while getopts h46 opt; do

J'ai affiché la fonction "show_help" à chaque message d'erreur, car la personne qui va l'utiliser n'aura pas forcément l'idée de faire -h.
Bonne idée :)

vivien

  • Administrateur
  • *
  • Messages: 47 213
    • Twitter LaFibre.info
bash: verifier les arguments passés à un script
« Réponse #7 le: 28 janvier 2022 à 17:03:48 »
Merci.

Le script final pour ceux que cela intéresse de générer du trafic https à un débit précis :

gen-trafic.sh
#!/bin/bash
# Script pour générer un trafic https avec un débit moyen indiqué en argument
# dépendance : wget (déjà préinstallée avec Ubuntu)
# Version du 28 janvier 2022 créé par Vivien Guéant
# Ce script est un logiciel libre que vous pouvez redistribuer ou modifier suivant la GNU GPLv3

show_help() {
cat << EOF
Utilisation: ${0##*/} [-h|-4|-6] [débit]

Génère un trafic HTTPS avec un "débit" en bit/s (100 kbit/s par défaut). Le débit, un nombre entier, peut être suffixé par les multiplicateurs "K", "M" ou "G" (non sensible à la casse), respectivement pour kbit/s, Mbit/s ou Gbit/s. Exemple : 1M = 1 Mbit/s. Le débit minimum est de 100 kbit/s, le débit maximum est de 1 Gbit/s.
Par défaut, utilisation du protocole IPv6 si disponible, sinon IPv4.

OPTIONS :
   -h affiche cette aide et quitte (ignore les autres options ou paramètres)
   -4 forcer le protocole IPv4
   -6 forcer le protocole IPv6
EOF
}

# Initialisation des variables
url="https://ubuntu.lafibre.info/10G.iso"
val=100
unit=k
protocol=
min=$((100*1000))
max=$((1*1000*1000*1000))

# Vérification de la validité des arguments passés en paramètres
OPTIND=1
while getopts :h46 opt; do
case $opt in
h) show_help ; exit 0 ;;
4) protocol="-4 " ;;
6) protocol="-6 " ;;
*) printf 'Option inconnue : %s\n\n' "$1" >&2 ; show_help ; exit 1 ;;
esac
done
shift "$((OPTIND-1))"

arg="$@"
if [ -n "$arg" ] ; then
regex="^([1-9][0-9]*)(k|K|m|M|g|G)?$"
if [[ $arg =~ $regex ]] ; then
val=${BASH_REMATCH[1]}
unit=${BASH_REMATCH[2]}
else
printf "Le débit '$arg' est invalide.\n\n" >&2
show_help ; exit 1
fi
fi

case $unit in
k|K) mult=1000 ;;
m|M) mult=$((1000*1000)) ;;
g|G) mult=$((1000*1000*1000)) ;;
*) mult=1 ;;
esac

rate=$((val*mult))

if (( rate < min )) || (( rate > max )); then
printf "Le débit '$arg' est hors des limites (minimum de 100 kbit/s, maximum de 1 Gbit/s).\n\n" >&2
show_help ; exit 1
fi

# Calcul de débit en kbit/s et en octets par seconde
ratekb=$((rate / 1000))
ratebyte=$((rate / 8))

# Lancement de wget (boucle infinie)
printf "Génération d'un trafic https de $ratekb kbit/s (soit $ratebyte octets par seconde).\n"
printf "Ctrl+C pour arrêter le transfert: maintenir la touche \"Ctrl\" enfoncée et appuyer sur la touche \"C\".\n\n"

while [ 1 ]
do
wget $protocol--limit-rate=$ratebyte -O /dev/null ${url}
done
exit 0