Exécuter des instructions sur plusieurs lignes dans la ligne de commande sur une seule ligne?


197

J'utilise Python avec -cpour exécuter une boucle à une ligne, c'est-à-dire:

$ python -c "for r in range(10): print 'rob'"

Cela fonctionne bien. Cependant, si j'importe un module avant la boucle for, j'obtiens une erreur de syntaxe:

$ python -c "import sys; for r in range(10): print 'rob'"
  File "<string>", line 1
    import sys; for r in range(10): print 'rob'
              ^
SyntaxError: invalid syntax

Une idée de comment cela peut être résolu?

Il est important pour moi de l'avoir en une seule ligne afin de pouvoir l'inclure dans un Makefile.


Réponses:


182

vous pourriez faire

echo -e "import sys\nfor r in range(10): print 'rob'" | python

ou sans tuyaux:

python -c "exec(\"import sys\nfor r in range(10): print 'rob'\")"

ou

(echo "import sys" ; echo "for r in range(10): print 'rob'") | python

ou la réponse de @ SilentGhost / la réponse de @ Crast


La dernière option fonctionne très bien avec python3 dans Windows
Ian Ellis

1
@RudolfOlah espère que vous le savez maintenant mais juste pour référence, vous devez envelopper l'instruction d'impression pour les versions python3 + comme:python -c "exec(\"import sys\nfor r in range(10): print('rob')\")"
systrigger

@systrigger merci, j'ai raté que je pense que j'étais pressé et je ne savais pas que heh

89

ce style peut également être utilisé dans les makefiles (et en fait, il est utilisé assez souvent).

python - <<EOF
import sys
for r in range(3): print 'rob'
EOF

ou

python - <<-EOF
    import sys
    for r in range(3): print 'rob'
EOF

dans ce dernier cas, les premiers caractères de tabulation sont également supprimés (et certaines perspectives structurées peuvent être obtenues)

au lieu de EOF, un mot marqueur n'apparaît pas dans le document ici au début d'une ligne (voir aussi ici les documents dans la page de manuel bash ou ici ).


9
Agréable. Pour également passer des arguments , placez-les simplement après <<EOF. Notez, cependant, qu'il est préférable de citer le délimiteur - par exemple, <<'EOF'- afin de protéger le contenu du document ici contre les extensions de shell initiales.
mklement0

56

Le problème n'est pas réellement avec l'instruction import, c'est avec tout ce qui se trouve avant la boucle for. Ou plus précisément, tout ce qui apparaît devant un bloc en ligne.

Par exemple, tout cela fonctionne:

python -c "import sys; print 'rob'"
python -c "import sys; sys.stdout.write('rob\n')"

Si l'importation en tant que déclaration était un problème, cela fonctionnerait, mais cela ne fonctionne pas:

python -c "__import__('sys'); for r in range(10): print 'rob'"

Pour votre exemple très basique, vous pouvez le réécrire comme ceci:

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"

Cependant, les lambdas ne peuvent exécuter que des expressions, pas des instructions ou des instructions multiples, il est donc possible que vous ne puissiez toujours pas faire ce que vous voulez faire. Cependant, entre les expressions de générateur, la compréhension de liste, lambdas, sys.stdout.write, le "map" intégré et certaines interpolations de chaînes créatives, vous pouvez faire de puissantes lignes simples.

La question est, jusqu'où voulez-vous aller, et à quel moment ne vaut-il pas mieux écrire un petit .pyfichier que votre makefile exécute à la place?


31


- Pour que cette réponse fonctionne également avec Python 3.x , printest appelé comme une fonction : dans 3.x, ne print('foo') fonctionne que, tandis que 2.x accepte également print 'foo'.
- Pour une perspective multiplateforme qui inclut Windows , voir la réponse utile de kxr .

Dans bash, kshouzsh :

Utilisez une chaîne entre guillemets C ANSI ( $'...'), qui permet d'utiliser \npour représenter les sauts de ligne qui sont étendus aux sauts de ligne réels avant que la chaîne ne soit passée à python:

python -c $'import sys\nfor r in range(10): print("rob")'

Notez les instructions \nentre importet forpour effectuer un saut de ligne.

Pour passer des valeurs de variable shell à une telle commande, il est plus sûr d'utiliser des arguments et d'y accéder via sys.argvle script Python:

name='rob' # value to pass to the Python script
python -c $'import sys\nfor r in range(10): print(sys.argv[1])' "$name"

Voir ci-dessous pour une discussion sur les avantages et les inconvénients de l'utilisation d'une chaîne de commande (pré-traitée avec séquence d'échappement) entre guillemets doubles avec des références de variables shell intégrées .

Pour travailler en toute sécurité avec des $'...'cordes:

  • Doublez les \ instances dans votre code source d' origine .
    • \<char>- des séquences telles que \ndans ce cas, mais également les suspects habituels tels que \t, \r, \b- sont étendus par $'...'(voir man printfles fuites pris en charge)
  • Échapper les 'instances en tant que \'.

Si vous devez rester conforme à POSIX :

Utiliser printfavec une substitution de commande :

python -c "$(printf %b 'import sys\nfor r in range(10): print("rob")')"

Pour travailler en toute sécurité avec ce type de chaîne:

  • Doublez les \ instances dans votre code source d' origine .
    • \<char>séquences - comme \ndans ce cas, mais aussi les suspects habituels tels que \t, \r, \b- sont élargit la portée printf(voir man printfles séquences d'échappement pris en charge).
  • Passez une simple cité chaîne à printf %bet échapper à des guillemets simples incorporés comme '\'' (sic).

    • L'utilisation de guillemets simples protège le contenu de la chaîne de toute interprétation par le shell .

      • Cela dit, pour les scripts Python courts (comme dans ce cas), vous pouvez utiliser une chaîne entre guillemets doubles pour incorporer des valeurs de variable shell dans vos scripts - tant que vous êtes au courant des pièges associés (voir le point suivant); par exemple, le shell se développe $HOMEdans le répertoire personnel de l'utilisateur actuel. dans la commande suivante:

        • python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")"
      • Cependant, l'approche généralement préférée est de passer des valeurs du shell via des arguments et d'y accéder via sys.argvPython; l'équivalent de la commande ci-dessus est:

        • python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
    • Bien que l'utilisation d'une chaîne entre guillemets doubles soit plus pratique - elle vous permet d'utiliser des guillemets simples intégrés sans échappement et des guillemets doubles incorporés comme \"- elle rend également la chaîne sujette à interprétation par le shell , ce qui peut ou non être l'intention; $et les `caractères de votre code source qui ne sont pas destinés au shell peuvent provoquer une erreur de syntaxe ou modifier la chaîne de manière inattendue.

      • De plus, le propre \traitement du shell dans des chaînes entre guillemets doubles peut gêner; par exemple, pour que Python produise une sortie littérale ro\b, vous devez y passer ro\\b; avec une '...'chaîne shell et des instances doublées \ , nous obtenons:
        python -c "$(printf %b 'import sys\nprint("ro\\\\bs")')" # ok: 'ro\bs'
        En revanche, cela ne fonctionne pas comme prévu avec une "..."chaîne shell:
        python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs'
        le shell interprète à la fois "\b" et "\\b"comme littéral \b, nécessitant un nombre vertigineux d' \instances supplémentaires pour obtenir l'effet souhaité:
        python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"

Pour passer le code viastdin plutôt que -c:

Remarque: je me concentre ici sur les solutions unifilaires; La réponse de xorho montre comment utiliser un document multi-lignes ici - assurez-vous de citer le délimiteur, cependant; par exemple, à <<'EOF'moins que vous ne souhaitiez explicitement que le shell développe la chaîne à l'avant (ce qui est fourni avec les mises en garde mentionnées ci-dessus).


Dans bash, kshouzsh :

Combinez une chaîne entre guillemets C ANSI ( $'...') avec une chaîne ici ( <<<...):

python - <<<$'import sys\nfor r in range(10): print("rob")'

-indique pythonexplicitement de lire depuis stdin (ce qu'il fait par défaut). -est facultatif dans ce cas, mais si vous souhaitez également passer des arguments aux scripts, vous en avez besoin pour lever l'ambiguïté d'un nom de fichier de script:

python - 'rob' <<<$'import sys\nfor r in range(10): print(sys.argv[1])'

Si vous devez rester conforme à POSIX :

Utilisez printfcomme ci-dessus, mais avec un pipeline afin de passer sa sortie via stdin:

printf %b 'import sys\nfor r in range(10): print("rob")' | python

Avec un argument:

printf %b 'import sys\nfor r in range(10): print(sys.argv[1])' | python - 'rob'

2
Cela devrait être la réponse élue!
débuts le

1
Cela fonctionne également et est probablement la meilleure réponse car il comprend une explication complète, bravo!

22

Une idée de comment cela peut être résolu?

Votre problème est ;dû au fait que les instructions Python, séparées par , ne peuvent être que des "petites instructions", qui sont toutes à une ligne. À partir du fichier de grammaire dans les documents Python :

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
             import_stmt | global_stmt | nonlocal_stmt | assert_stmt)

Les instructions composées ne peuvent pas être incluses sur la même ligne avec d'autres instructions via des points-virgules - il est donc -ctrès difficile de le faire avec l' indicateur.

Lors de la démonstration de Python dans un environnement shell bash, je trouve très utile d'inclure des instructions composées. La seule façon simple de le faire de manière fiable est avec heredocs (une chose shell posix).

Heredocs

Utilisez un heredoc (créé avec <<) et Python option d'interface de ligne de commande , -:

$ python - <<-"EOF"
        import sys                    # 1 tab indent
        for r in range(10):           # 1 tab indent
            print('rob')              # 1 tab indent and 4 spaces
EOF

L'ajout de l' -after <<(le <<-) vous permet d'utiliser des tabulations pour mettre en retrait (Stackoverflow convertit les tabulations en espaces, j'ai donc mis en retrait 8 espaces pour le souligner). Les onglets de tête seront supprimés.

Vous pouvez le faire sans les onglets avec juste <<:

$ python - << "EOF"
import sys
for r in range(10):
    print('rob')
EOF

Mettre des guillemets autour EOFempêche l' expansion des paramètres et arithmétique . Cela rend l'hérédoc plus robuste.

Bash multiline strings

Si vous utilisez des guillemets doubles, vous obtiendrez une expansion du shell:

$ python -c "
> import sys
> for p in '$PATH'.split(':'):
>     print(p)
> "
/usr/sbin
/usr/bin
/sbin
/bin
...

Pour éviter l'expansion du shell, utilisez des guillemets simples:

$ python -c '
> import sys
> for p in "$PATH".split(":"):
>     print(p)
> '
$PATH

Notez que nous devons échanger les caractères de citation sur les littéraux en Python - nous ne pouvons pas utiliser le caractère de citation interprété par BASH. Nous pouvons cependant les alterner, comme nous le pouvons en Python - mais cela semble déjà assez déroutant, c'est pourquoi je ne recommande pas ceci:

$ python -c '
import sys
for p in "'"$PATH"'".split(":"):
    print(p)
'
/usr/sbin
/usr/bin
/sbin
/bin
...

Critique de la réponse acceptée (et autres)

Ce n'est pas très lisible:

echo -e "import sys\nfor r in range(10): print 'rob'" | python

Pas très lisible, et en plus difficile à déboguer en cas d'erreur:

python -c "exec(\"import sys\\nfor r in range(10): print 'rob'\")"

Peut-être un peu plus lisible, mais tout de même assez moche:

(echo "import sys" ; echo "for r in range(10): print 'rob'") | python

Vous passerez un mauvais moment si vous en avez "dans votre python:

$ python -c "import sys
> for r in range(10): print 'rob'"

N'abusez pas mapet ne répertoriez pas les compréhensions pour obtenir des boucles:

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"

Ce sont tous tristes et mauvais. Ne les fais pas.


3
++ pour les informations de grammaire; le doc ici (non extensible) est pratique et la solution la plus robuste, mais évidemment pas un one-liner. Si une seule solution en ligne est un must, en utilisant une chaîne entre guillemets C ANSI ( bash, kshou zsh) est une solution raisonnable: python -c $'import sys\nfor r in range(10): print(\'rob\')'(vous aurez seulement à vous soucier de sortir des guillemets simples (que vous pouvez éviter en utilisant des guillemets doubles) et barres obliques inverses).
mklement0

14

utilisez simplement return et tapez-le sur la ligne suivante:

user@host:~$ python -c "import sys
> for r in range(10): print 'rob'"
rob
rob
...

6
Sérieusement, vous allez vous fouler quelque chose si vous continuez à faire ça. python $(srcdir)/myscript.pypour une grande justice.
Jason Orendorff

10

$ python2.6 -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"

Fonctionne bien. Utilisez "[]" pour aligner votre boucle for.


9

Le problème n'est pas avec la importdéclaration. Le problème est que les instructions de flux de contrôle ne fonctionnent pas en ligne dans une commande python. Remplacez cette importinstruction par toute autre instruction et vous verrez le même problème.

Pensez-y: python ne peut pas tout intégrer. Il utilise l'indentation pour regrouper le flux de contrôle.


7

Si votre système est compatible Posix.2, il devrait fournir l' printfutilitaire:

$ printf "print 'zap'\nfor r in range(3): print 'rob'" | python
zap
rob
rob
rob

2
Bonne solution, mais je suggère d'utiliser printf %b '...' | pythonpour plus de robustesse, car cela empêche printfd'interpréter des séquences telles que %d(spécificateurs de format) dans la chaîne d'entrée. De plus, à moins que vous ne souhaitiez explicitement appliquer des extensions de shell à votre chaîne de commande Python à l'avance (ce qui peut prêter à confusion), il est préférable d'utiliser '(guillemets simples) pour les citations externes, afin d'éviter à la fois les extensions et le traitement de jeu que le shell applique. aux chaînes entre guillemets doubles.
mklement0

5

single/double quoteset backslashpartout:

$ python -c 'exec("import sys\nfor i in range(10): print \"bob\"")'

Beaucoup mieux:

$ python -c '
> import sys
> for i in range(10):
>   print "bob"
> '

alors. beaucoup. mieux.
Marc

4

(Répondu le 23 novembre 10 à 19:48) Je ne suis pas vraiment un grand Pythoner - mais j'ai trouvé cette syntaxe une fois, j'ai oublié d'où, alors j'ai pensé la documenter:

si vous utilisez à la sys.stdout.writeplace de print( la différence étant, sys.stdout.writeprend les arguments comme une fonction, entre parenthèses - alors printque non ), alors pour une ligne, vous pouvez vous en sortir en inversant l'ordre de la commande et en forsupprimant le point-virgule, et mettre la commande entre crochets, c'est-à-dire:

python -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"

Je n'ai aucune idée de la façon dont cette syntaxe serait appelée en Python :)

J'espère que cela t'aides,

À votre santé!


(EDIT Tue Apr 9 20:57:30 2013) Eh bien, je pense que j'ai finalement trouvé de quoi parlaient ces crochets dans les lignes simples ; ce sont des «compréhensions de liste» (apparemment); notez d'abord cela dans Python 2.7:

$ STR=abc
$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); print a"
<generator object <genexpr> at 0xb771461c>

Ainsi, la commande entre crochets / parenthèses est considérée comme un "objet générateur"; si nous "itérons" à travers elle en appelant next()- alors la commande à l'intérieur de la parenthèse sera exécutée (notez "abc" dans la sortie):

$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); a.next() ; print a"
abc
<generator object <genexpr> at 0xb777b734>

Si nous utilisons maintenant des crochets - notez que nous n'avons pas besoin d'appeler next()pour que la commande s'exécute, elle s'exécute immédiatement lors de l'affectation; Cependant, une inspection ultérieure révèle que aest None:

$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; print a"
abc
[None]

Cela ne laisse pas beaucoup d'informations à rechercher, pour le cas des crochets - mais je suis tombé sur cette page qui, je pense, explique:

Trucs et astuces Python - Première édition - Tutoriels Python | Dream.In.Code :

Si vous vous souvenez, le format standard d'un générateur de ligne unique est une sorte de boucle d'une ligne «pour» entre crochets. Cela produira un objet itérable à un coup qui est un objet sur lequel vous pouvez itérer dans une seule direction et que vous ne pouvez pas réutiliser une fois que vous avez atteint la fin.

Une «compréhension de liste» ressemble presque à un générateur ordinaire sur une seule ligne, sauf que les crochets réguliers - () - sont remplacés par des crochets - []. L'avantage majeur de la compréhension des listes est qu'il produit une `` liste '', plutôt qu'un objet itérable `` à un coup '', de sorte que vous pouvez aller et venir à travers lui, ajouter des éléments, trier, etc.

Et en effet, c'est une liste - c'est juste que son premier élément devient nul dès qu'il est exécuté:

$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin].__class__"
abc
<type 'list'>
$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin][0]"
abc
None

Les compréhensions de liste sont par ailleurs documentées en 5. Structures de données: 5.1.4. Liste des compréhensions - La documentation de Python v2.7.4 comme "Les compréhensions de liste fournissent un moyen concis de créer des listes"; on peut supposer que c'est là que l '«exécutabilité» limitée des listes entre en jeu dans les lignes simples.

Eh bien, j'espère que je ne suis pas trop loin de la réalité ici ...

EDIT2: et voici une ligne de commande à une ligne avec deux boucles for non imbriquées; tous deux placés entre crochets "compréhension de liste":

$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; b=[sys.stdout.write(str(x)) for x in range(2)] ; print a ; print b"
abc
01[None]
[None, None]

Notez que la deuxième "liste" a bmaintenant deux éléments, car sa boucle for a explicitement fonctionné deux fois; cependant, le résultat de sys.stdout.write()dans les deux cas était (apparemment) None.


4

Cette variante est la plus portable pour mettre des scripts multi-lignes en ligne de commande sur Windows et * nix, py2 / 3, sans canaux:

python -c "exec(\"import sys \nfor r in range(10): print('rob') \")"

(Aucun des autres exemples vus jusqu'ici ne l'a fait)

Neat sur Windows, c'est:

python -c exec"""import sys \nfor r in range(10): print 'rob' """
python -c exec("""import sys \nfor r in range(10): print('rob') """)

Neat sur bash / * nix est:

python -c $'import sys \nfor r in range(10): print("rob")'

Cette fonction transforme n'importe quel script multiligne en une commande portable à ligne unique:

def py2cmdline(script):
    exs = 'exec(%r)' % re.sub('\r\n|\r', '\n', script.rstrip())
    print('python -c "%s"' % exs.replace('"', r'\"'))

Usage:

>>> py2cmdline(getcliptext())
python -c "exec('print \'AA\tA\'\ntry:\n for i in 1, 2, 3:\n  print i / 0\nexcept:\n print \"\"\"longer\nmessage\"\"\"')"

L'entrée était:

print 'AA   A'
try:
 for i in 1, 2, 3:
  print i / 0
except:
 print """longer
message"""

++ pour l'angle multiplateforme et le convertisseur. Votre première commande est aussi bonne que possible en termes de portabilité (en laissant PowerShell de côté), mais en fin de compte il n'y a pas de syntaxe multiplateforme unique et entièrement robuste , car la nécessité d'utiliser des guillemets doubles comporte alors le risque d'expansions de shell indésirables, avec Windows nécessitant l'échappement de caractères différents des shells de type POSIX. Dans PowerShell v3 ou supérieur, vous pouvez faire fonctionner vos lignes de commande en insérant l'option "stop-parsing" --%avant l'argument de chaîne de commande.
mklement0

@ mklement0 " extensions de shell indésirables ": eh bien, l'insertion d'extensions de shell dans quelque chose comme print "path is %%PATH%%"resp. print "path is $PATH"est généralement l'option que l'on veut dans un script ou une ligne de commande - à moins que l'on n'échappe aux choses comme d'habitude pour la plate-forme. Même chose avec d'autres langues. (La syntaxe Python elle-même ne suggère pas régulièrement l'utilisation des% et des $ de manière concurrente.)
kxr

Si vous insérez des références de variables shell directement dans le code source Python, il ne sera par définition pas portable. Mon point est que même si vous avez plutôt construit des références spécifiques à la plate-forme dans des variables distinctes que vous passez comme arguments à une seule commande Python "sans shell" , cela peut ne pas toujours fonctionner, car vous ne pouvez pas protéger la chaîne entre guillemets : par exemple, que faire si vous avez besoin d'un littéral $foo dans votre code Python? Si vous y échappez \$fooau profit des obus de type POSIX, vous cmd.exeverrez toujours le supplément \ . C'est peut-être rare, mais ça vaut le coup d'être connu.
mklement0

J'essaie de le faire dans Windows PowerShell, mais le problème est que python -c exec ("" "..." "") ne produit aucune sortie, que le code dans ... puisse être exécuté ou pas; Je pourrais y mettre n'importe quel charabia, et le résultat serait le même. J'ai l'impression que la coquille "mange" à la fois les flux stdout et stderr - comment puis-je les faire cracher?
Yury

2

Ce script fournit une interface de ligne de commande de type Perl:

Pyliner - Script pour exécuter du code Python arbitraire sur la ligne de commande (recette Python)


Je pense qu'ils voulaient quelque chose pour résoudre ce problème, ne pas utiliser un autre outil. Bref, bon indice
enrico.bacis

Je suis d'accord avec @ enrico.bacis, mais je suis toujours heureux que vous ayez ajouté cette réponse. Il répond à la question que j'avais lorsque j'ai recherché cette page sur Google.
tbc0

1

Quand je devais faire ça, j'utilise

python -c "$(echo -e "import sys\nsys.stdout.write('Hello World!\\\n')")"

Notez la triple barre oblique inverse pour la nouvelle ligne dans l'instruction sys.stdout.write.


Cela fonctionne, mais depuis que vous utilisez echo -e, ce qui est non standard et nécessite bash, kshou zsh, vous pouvez aussi bien utiliser une $'...'chaîne directement, ce qui simplifie également la fuite:python -c $'import sys\nsys.stdout.write("Hello World!\\n")'
mklement0

Cette réponse fonctionne, les autres réponses ne fonctionnent pas pour Python3

1

Je voulais une solution avec les propriétés suivantes:

  1. Lisible
  2. Lire stdin pour traiter la sortie d'autres outils

Les deux exigences n'étaient pas fournies dans les autres réponses, alors voici comment lire stdin tout en faisant tout sur la ligne de commande:

grep special_string -r | sort | python3 <(cat <<EOF
import sys
for line in sys.stdin:
    tokens = line.split()
    if len(tokens) == 4:
        print("%-45s %7.3f    %s    %s" % (tokens[0], float(tokens[1]), tokens[2], tokens[3]))
EOF
)

0

il y a une option de plus, sys.stdout.write renvoie None, qui garde la liste vide

cat somefile.log | python -c "import sys; [ligne pour ligne dans sys.stdin si sys.stdout.write (ligne * 2)]"


0

Si vous ne voulez pas toucher stdin et simuler comme si vous aviez passé "python cmdfile.py", vous pouvez faire ce qui suit à partir d'un shell bash:

$ python  <(printf "word=raw_input('Enter word: ')\nimport sys\nfor i in range(5):\n    print(word)")

Comme vous pouvez le voir, il vous permet d'utiliser stdin pour lire les données d'entrée. En interne, le shell crée le fichier temporaire pour le contenu de la commande d'entrée.


++ pour ne pas "utiliser" stdin avec le script lui-même (bien -c "$(...)" fait la même chose et est compatible POSIX); pour donner <(...)un nom à la construction: substitution de processus ; il fonctionne également dans kshet zsh.
mklement0
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.