Comment analyser les arguments de ligne de commande en Python

Photo of author

By pierre



Vous cherchez à exécuter des scripts Python en y intégrant des paramètres via la ligne de commande ? Découvrez comment interpréter ces arguments à l’aide des modules sys, getopt et argparse en Python.

En Python, pour obtenir une saisie utilisateur, vous utilisez généralement la fonction `input()`. Cependant, certaines applications nécessitent de transmettre des informations au script lors de son lancement en ligne de commande.

Ce tutoriel vous guidera à travers l’exécution d’un script Python avec des options et des arguments spécifiés directement lors de son appel. Nous allons explorer comment utiliser les modules natifs de Python pour décortiquer ces options et arguments.

C’est parti !

Comprendre `sys.argv` en Python

Si vous avez déjà programmé en C, vous savez que la ligne de commande est une méthode courante pour transmettre des données à un programme. Pour cela, la fonction `main` est structurée de manière spécifique :

#include<stdio.h>

int main(int argc, char **argv){
    //argc: nombre d'arguments
    //argv: tableau d'arguments
    
    //traitement des arguments

    return 0;
}

Dans ce contexte, `argc` représente le nombre d’arguments et `argv` est un tableau contenant ces arguments.

Exécuter des scripts Python avec des paramètres de ligne de commande

En Python, vous lancez un script via la ligne de commande avec la syntaxe `python3 nom_du_fichier.py`. De plus, vous pouvez ajouter autant d’arguments que nécessaire après le nom du fichier :

$ python3 nom_du_fichier.py param1 param2 ... paramN

Le module `sys` facilite l’accès et le traitement de ces arguments. `sys.argv` est une liste contenant tous les arguments fournis lors du lancement du script.

Par exemple, si nous lançons `main.py` avec différents arguments :

$ python3 main.py bonjour monde python script

Nous pouvons examiner cette liste en utilisant une boucle `for` combinée à la fonction `enumerate` :

# main.py

import sys

for index, argument in enumerate(sys.argv):
    print(f"argument{index}: {argument}")
# Résultat
argument0: main.py
argument1: bonjour
argument2: monde
argument3: python
argument4: script

On constate que le premier élément (à l’index 0) correspond au nom du script lui-même, et les arguments suivants commencent à l’index 1.

Ce code simple permet de récupérer et de manipuler les arguments passés en ligne de commande. Cependant, cela soulève quelques questions :

  • Comment l’utilisateur sait-il quels arguments sont attendus ?
  • Quelle est la signification de chaque argument ?

La réponse n’est pas évidente. Pour résoudre ce problème, les modules `getopt` ou `argparse` sont très utiles. Nous allons les explorer dans les sections suivantes.✅

Interprétation des arguments de ligne de commande avec `getopt` de Python

Voyons comment analyser les arguments en utilisant le module intégré `getopt`.

Après avoir importé `getopt` depuis le module `getopt`, vous pouvez définir les arguments à interpréter, ainsi que les options courtes et longues associées. Il est important de noter que nous devons analyser les arguments à partir de l’index 1 de `sys.argv`. Par conséquent, la portion à analyser est `sys.argv[1:]`.

Dans notre exemple, nous allons manipuler un message et un nom de fichier. Nous utiliserons les options courtes `m` et `f`, ainsi que les options longues `message` et `file`.

Mais comment indiquer qu’une option spécifique attend un argument ?

  • Pour les options courtes, ajoutez un deux-points (:) après la lettre de l’option.
  • Pour les options longues, ajoutez un signe égal (=) après le nom de l’option.

En appliquant ces règles, voici le code de `main.py` :

# main.py

import sys
from getopt import getopt

options, arguments_non_optionnels = getopt(sys.argv[1:], 'm:f:', ['message=', 'file='])

print(options)
print(arguments_non_optionnels)

Ici, la variable `options` contient une liste de tuples, où chaque tuple représente une option et sa valeur. La variable `arguments_non_optionnels` contient tous les arguments positionnels qui n’ont pas été reconnus comme des options.

Nous pouvons fournir le message et le nom du fichier via les options courtes ou longues.

En exécutant `main.py` avec les options longues :

$ python3 main.py --message bonjour --file fichier.txt

Les options et leurs valeurs sont regroupées dans des tuples au sein de la variable `options`. Comme aucun argument positionnel n’a été fourni, `arguments_non_optionnels` est une liste vide.

# Résultat
[('--message', 'bonjour'), ('--file', 'fichier.txt')]
[]

De la même manière, nous pouvons utiliser les options courtes :

$ python3 main.py -m bonjour -f fichier.txt
# Résultat
[('-m', 'bonjour'), ('-f', 'fichier.txt')]
[]

⚠️ L’option courte `-m` dans cet exemple ne doit pas être confondue avec l’indicateur de ligne de commande `-m` qui permet de lancer un module en tant que programme principal lors de l’exécution d’un script Python.

Par exemple, `python3 -m unittest main.py` exécuterait les tests unitaires en considérant `main.py` comme le point d’entrée.

Nous avons mentionné que les arguments positionnels restants sont stockés dans `arguments_non_optionnels`. Voici un exemple :

$ python3 main.py -m bonjour -f fichier.txt argument_supplementaire

La liste `arguments_non_optionnels` contient l’argument `argument_supplementaire`.

# Résultat
[('-m', 'bonjour'), ('-f', 'fichier.txt')]
['argument_supplementaire']

Puisque `options` est une liste de tuples, nous pouvons la parcourir pour extraire les arguments associés à chaque option.

Maintenant, que faisons-nous du nom du fichier et du message après les avoir extraits ? Nous allons ouvrir le fichier en mode écriture et y écrire le message, converti en majuscules.

# main.py
import sys
from getopt import getopt

options, arguments_non_optionnels = getopt(sys.argv[1:], 'm:f:', ['message=', 'file='])

print(options)
print(arguments_non_optionnels)

for option, argument in options:
    if option == '-m':
        message = argument
    if option == '-f':
        file = argument

with open(file, 'w') as f:
    f.write(message.upper())

Exécutons `main.py` avec les options courtes :

$ python main.py -m bonjour -f fichier_cible.txt
[('-m', 'bonjour'), ('-f', 'fichier_cible.txt')]
[]

Après l’exécution de `main.py`, nous pouvons observer que `fichier_cible.txt` a été créé dans notre répertoire de travail. Il contient le mot ‘bonjour’ en majuscules (‘BONJOUR’).

$ ls
main.py  fichier_cible.txt
$ cat fichier_cible.txt
BONJOUR

Comment interpréter les arguments de ligne de commande avec `argparse`

Le module `argparse`, également intégré à la bibliothèque standard de Python, fournit des outils pour interpréter les arguments de ligne de commande et pour structurer des interfaces en ligne de commande.

Pour analyser les arguments, nous importons la classe `ArgumentParser` du module `argparse`. Nous créons ensuite une instance, `analyseur_arguments` de cette classe.

from argparse import ArgumentParser

analyseur_arguments = ArgumentParser()

Nous souhaitons définir deux arguments :

  • `message` : la chaîne de texte à traiter.
  • `file` : le nom du fichier avec lequel interagir.

Nous utilisons la méthode `add_argument()` de l’objet `analyseur_arguments` pour définir ces arguments. L’argument `help` sert à définir une description pour chaque paramètre.

analyseur_arguments.add_argument('message', help='Chaîne de texte')
analyseur_arguments.add_argument('file', help='Nom du fichier')

Jusqu’à présent, nous avons initialisé `analyseur_arguments` et défini les arguments de ligne de commande. Lors de l’exécution du script, la méthode `parse_args()` d’`analyseur_arguments` extrait les valeurs des arguments.

Les résultats sont stockés dans la variable `arguments`. Les valeurs des arguments sont ensuite accessibles via la syntaxe `arguments.nom_de_l_argument`.

Après avoir récupéré les valeurs des arguments, nous allons écrire le message, en inversant la casse des lettres (avec la méthode `swapcase()`), dans le fichier.

arguments = analyseur_arguments.parse_args()

message = arguments.message
file = arguments.file

with open(file, 'w') as f:
     f.write(message.swapcase())

En combinant les étapes précédentes, voici le code complet du fichier `main.py` :

# main.py

from argparse import ArgumentParser

analyseur_arguments = ArgumentParser()
analyseur_arguments.add_argument('message', help='Chaîne de texte')
analyseur_arguments.add_argument('file', help='Nom du fichier')

arguments = analyseur_arguments.parse_args()
print(arguments)

message = arguments.message
file = arguments.file

with open(file, 'w') as f:
     f.write(message.swapcase())

Comprendre l’utilisation des arguments de ligne de commande

Pour comprendre l’usage des arguments lors de l’exécution de `main.py`, vous pouvez utiliser l’option longue `–help` :

$ python3 main.py --help
usage: main.py [-h] message file

positional arguments:
  message     Chaîne de texte
  file        Nom du fichier

optional arguments:
  -h, --help  Montrer ce message d'aide et quitter

Il n’y a pas d’arguments optionnels. `message` et `file` sont des arguments positionnels obligatoires. L’option courte `-h` est également valide :

$ python3 main.py -h
usage: main.py [-h] message file

positional arguments:
  message     Chaîne de texte
  file        Nom du fichier

optional arguments:
  -h, --help  Montrer ce message d'aide et quitter

Comme on le voit, les deux arguments sont positionnels par défaut. Si l’un de ces arguments est manquant, une erreur sera générée.

Dans l’exemple suivant, l’argument positionnel ‘Bonjour’ est fourni pour le message, mais pas le nom du fichier.

L’erreur indique que l’argument `file` est requis.

$ python3 main.py Bonjour
usage: main.py [-h] message file
main.py: error: les arguments suivants sont nécessaires: file

Lorsque les deux arguments positionnels sont fournis, on observe que l’espace de noms des arguments contient les valeurs correspondantes.

$ python3 main.py Bonjour fichier1.txt
# Résultat
Namespace(file='fichier1.txt', message='Bonjour')

Si nous examinons le contenu du répertoire courant, on constate que le script a créé le fichier `fichier1.txt` :

$ ls
fichier1.txt  main.py

Le contenu du fichier `fichier1.txt` correspond à la chaîne ‘Bonjour’ dont la casse des lettres a été inversée : ‘bONJOUR’.

$ cat fichier1.txt
bONJOUR

Comment rendre les arguments de ligne de commande optionnels

Pour rendre ces arguments optionnels, il suffit de les préfixer avec `–`.

Modifions `main.py` pour que `message` et `file` deviennent optionnels.

# main.py

from argparse import ArgumentParser

analyseur_arguments = ArgumentParser()
analyseur_arguments.add_argument('--message', help='Chaîne de texte')
analyseur_arguments.add_argument('--file', help='Nom du fichier')

Puisque les arguments sont optionnels, nous pouvons définir des valeurs par défaut.

if arguments.message and arguments.file:
    message = arguments.message
    file = arguments.file
else:
    message='Python3'
    file='mon_fichier.txt'

Le contenu du fichier `main.py` est maintenant le suivant :

# main.py

from argparse import ArgumentParser

analyseur_arguments = ArgumentParser()
analyseur_arguments.add_argument('--message', help='Chaîne de texte')
analyseur_arguments.add_argument('--file', help='Nom du fichier')

arguments = analyseur_arguments.parse_args()
print(arguments)

if arguments.message and arguments.file:
    message = arguments.message
    file = arguments.file
else:
    message='Python3'
    file='mon_fichier.txt'

with open(file, 'w') as f:
     f.write(message.swapcase())

Si nous consultons l’aide, nous voyons que `message` et `file` sont devenus optionnels. Il est donc possible de lancer `main.py` sans ces arguments.

$ python3 main.py --help
usage: main.py [-h] [--message MESSAGE] [--file FILE]

optional arguments:
  -h, --help         Montrer ce message d'aide et quitter
  --message MESSAGE  Chaîne de texte
  --file FILE        Nom du fichier
$ python3 main.py

Dans l’espace de noms des arguments, `file` et `message` sont `None`.

# Résultat
Namespace(file=None, message=None)

Les valeurs par défaut `mon_fichier.txt` et `Python3` sont utilisées. Le fichier `mon_fichier.txt` est présent dans le répertoire de travail :

$ ls
fichier1.txt  main.py  mon_fichier.txt

Il contient le mot ‘Python3’ avec la casse des lettres inversée : ‘pYTHON3’.

$ cat mon_fichier.txt
pYTHON3

Vous pouvez également utiliser les arguments `–message` et `–file` pour rendre la ligne de commande plus explicite.

$ python3 main.py --message Codage --file fichier2.txt
# Résultat
Namespace(file='fichier2.txt', message='Codage')

`fichier2.txt` a été créé dans le répertoire de travail :

$ ls
fichier1.txt  fichier2.txt  main.py  mon_fichier.txt

Et il contient le mot ‘cODAGE’, comme prévu.

$ cat fichier2.txt
cODAGE

Conclusion

Voici un résumé des points importants abordés dans ce tutoriel :

  • Comme en langage C, vous pouvez accéder aux arguments de ligne de commande en Python via le tableau d’arguments `sys.argv`. `sys.argv[0]` est le nom du script Python. Nous nous intéressons donc à l’analyse de `sys.argv[1:]`.
  • Pour améliorer la lisibilité et pouvoir utiliser des options, il est préférable d’utiliser les modules `getopt` ou `argparse`.
  • Le module `getopt` permet d’analyser les arguments de ligne de commande à partir de l’index 1. Vous pouvez définir des options courtes et longues.
  • Lorsqu’une option attend un argument, vous devez ajouter deux-points (:) après l’option courte et un signe égal (=) après l’option longue.
  • Avec le module `argparse`, vous pouvez créer un objet `ArgumentParser` et utiliser la méthode `add_argument()` pour ajouter un argument positionnel obligatoire. Utilisez `–` avant le nom d’un argument pour le rendre optionnel.
  • Pour extraire les valeurs des arguments, appelez la méthode `parse_args()` sur l’objet `ArgumentParser`.

Maintenant, vous pouvez approfondir vos connaissances sur le hachage sécurisé en Python.