J'utilise Python avec -c
pour 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.
python
shell
command-line
heredoc
martineau
la source
la source
Réponses:
vous pourriez faire
ou sans tuyaux:
ou
ou la réponse de @ SilentGhost / la réponse de @ Crast
la source
python -c "exec(\"import sys\nfor r in range(10): print('rob')\")"
ce style peut également être utilisé dans les makefiles (et en fait, il est utilisé assez souvent).
ou
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 ).
la source
<<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.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:
Si l'importation en tant que déclaration était un problème, cela fonctionnerait, mais cela ne fonctionne pas:
Pour votre exemple très basique, vous pouvez le réécrire comme ceci:
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
.py
fichier que votre makefile exécute à la place?la source
- Pour que cette réponse fonctionne également avec Python 3.x ,
print
est appelé comme une fonction : dans 3.x, neprint('foo')
fonctionne que, tandis que 2.x accepte égalementprint 'foo'
.- Pour une perspective multiplateforme qui inclut Windows , voir la réponse utile de kxr .
Dans
bash
,ksh
ouzsh
:Utilisez une chaîne entre guillemets C ANSI (
$'...'
), qui permet d'utiliser\n
pour 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
:Notez les instructions
\n
entreimport
etfor
pour 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.argv
le script Python: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:\
instances dans votre code source d' origine .\<char>
- des séquences telles que\n
dans ce cas, mais également les suspects habituels tels que\t
,\r
,\b
- sont étendus par$'...'
(voirman printf
les fuites pris en charge)'
instances en tant que\'
.Si vous devez rester conforme à POSIX :
Utiliser
printf
avec une substitution de commande :Pour travailler en toute sécurité avec ce type de chaîne:
\
instances dans votre code source d' origine .\<char>
séquences - comme\n
dans ce cas, mais aussi les suspects habituels tels que\t
,\r
,\b
- sont élargit la portéeprintf
(voirman printf
les séquences d'échappement pris en charge).Passez une simple cité chaîne à
printf %b
et é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
$HOME
dans 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.argv
Python; 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.\
traitement du shell dans des chaînes entre guillemets doubles peut gêner; par exemple, pour que Python produise une sortie littéralero\b
, vous devez y passerro\\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 via
stdin
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
,ksh
ouzsh
:Combinez une chaîne entre guillemets C ANSI (
$'...'
) avec une chaîne ici (<<<...
):-
indiquepython
explicitement 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:Si vous devez rester conforme à POSIX :
Utilisez
printf
comme ci-dessus, mais avec un pipeline afin de passer sa sortie via stdin:Avec un argument:
la source
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 :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
-c
trè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 ,-
: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
<<
:Mettre des guillemets autour
EOF
empê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:
Pour éviter l'expansion du shell, utilisez des guillemets simples:
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:
Critique de la réponse acceptée (et autres)
Ce n'est pas très lisible:
Pas très lisible, et en plus difficile à déboguer en cas d'erreur:
Peut-être un peu plus lisible, mais tout de même assez moche:
Vous passerez un mauvais moment si vous en avez
"
dans votre python:N'abusez pas
map
et ne répertoriez pas les compréhensions pour obtenir des boucles:Ce sont tous tristes et mauvais. Ne les fais pas.
la source
bash
,ksh
ouzsh
) 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).utilisez simplement return et tapez-le sur la ligne suivante:
la source
python $(srcdir)/myscript.py
pour une grande justice.$ python2.6 -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"
Fonctionne bien. Utilisez "[]" pour aligner votre boucle for.
la source
Le problème n'est pas avec la
import
déclaration. Le problème est que les instructions de flux de contrôle ne fonctionnent pas en ligne dans une commande python. Remplacez cetteimport
instruction 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.
la source
Si votre système est compatible Posix.2, il devrait fournir l'
printf
utilitaire:la source
printf %b '...' | python
pour plus de robustesse, car cela empêcheprintf
d'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.single/double quotes
etbackslash
partout:Beaucoup mieux:
la source
(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.write
place deprint
( la différence étant,sys.stdout.write
prend les arguments comme une fonction, entre parenthèses - alorsprint
que non ), alors pour une ligne, vous pouvez vous en sortir en inversant l'ordre de la commande et enfor
supprimant le point-virgule, et mettre la commande entre crochets, c'est-à-dire: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:
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):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 quea
estNone
: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 :
Et en effet, c'est une liste - c'est juste que son premier élément devient nul dès qu'il est exécuté:
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":
Notez que la deuxième "liste" a
b
maintenant deux éléments, car sa boucle for a explicitement fonctionné deux fois; cependant, le résultat desys.stdout.write()
dans les deux cas était (apparemment)None
.la source
Cette variante est la plus portable pour mettre des scripts multi-lignes en ligne de commande sur Windows et * nix, py2 / 3, sans canaux:
(Aucun des autres exemples vus jusqu'ici ne l'a fait)
Neat sur Windows, c'est:
Neat sur bash / * nix est:
Cette fonction transforme n'importe quel script multiligne en une commande portable à ligne unique:
Usage:
L'entrée était:
la source
--%
avant l'argument de chaîne de commande.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.)$foo
dans votre code Python? Si vous y échappez\$foo
au profit des obus de type POSIX, vouscmd.exe
verrez toujours le supplément\
. C'est peut-être rare, mais ça vaut le coup d'être connu.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)
la source
Quand je devais faire ça, j'utilise
Notez la triple barre oblique inverse pour la nouvelle ligne dans l'instruction sys.stdout.write.
la source
echo -e
, ce qui est non standard et nécessitebash
,ksh
ouzsh
, 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")'
Je voulais une solution avec les propriétés suivantes:
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:
la source
il y a une option de plus, sys.stdout.write renvoie None, qui garde la liste vide
la source
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:
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.
la source
-c "$(...)"
fait la même chose et est compatible POSIX); pour donner<(...)
un nom à la construction: substitution de processus ; il fonctionne également dansksh
etzsh
.