Ich verwende Python mit -c
, um eine Einzeiler-Schleife auszuführen, dh:
$ python -c "for r in range(10): print 'rob'"
Das funktioniert gut. Wenn ich jedoch ein Modul vor der for-Schleife importiere, wird ein Syntaxfehler angezeigt:
$ 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
Irgendeine Idee, wie dies behoben werden kann?
Es ist mir wichtig, dies als Einzeiler zu haben, damit ich es in ein Makefile aufnehmen kann.
python
shell
command-line
heredoc
Martineau
quelle
quelle
Antworten:
du könntest es tun
oder ohne Rohre:
oder
oder @ SilentGhosts Antwort / @ Crasts Antwort
quelle
python -c "exec(\"import sys\nfor r in range(10): print('rob')\")"
Dieser Stil kann auch in Makefiles verwendet werden (und tatsächlich wird er ziemlich oft verwendet).
oder
Im letzteren Fall werden auch führende Tabulatorzeichen entfernt (und es kann ein strukturierter Ausblick erzielt werden).
Anstelle von EOF kann jedes Markierungswort stehen, das nicht im Dokument hier am Anfang einer Zeile erscheint (siehe auch hier Dokumente in der Bash-Manpage oder hier ).
quelle
<<EOF
. Beachten Sie jedoch, dass es besser ist, das Trennzeichen zu zitieren - z. B.<<'EOF'
-, um den Inhalt des Here-Dokuments vor Erweiterungen der Shell im Voraus zu schützen .Das Problem liegt nicht in der import-Anweisung, sondern darin, dass sich etwas vor der for-Schleife befindet. Oder genauer gesagt, alles, was vor einem Inline-Block erscheint.
Zum Beispiel funktionieren diese alle:
Wenn der Import als Anweisung ein Problem wäre, würde dies funktionieren, aber es funktioniert nicht:
Für Ihr sehr einfaches Beispiel könnten Sie es wie folgt umschreiben:
Lambdas können jedoch nur Ausdrücke ausführen, keine Anweisungen oder mehrere Anweisungen, sodass Sie möglicherweise immer noch nicht in der Lage sind, das zu tun, was Sie tun möchten. Zwischen Generatorausdrücken, Listenverständnis, Lambdas, sys.stdout.write, der eingebauten "Map" und einer kreativen Zeichenfolgeninterpolation können Sie jedoch einige leistungsstarke Einzeiler erstellen.
Die Frage ist, wie weit möchten Sie gehen und an welchem Punkt ist es nicht besser, eine kleine
.py
Datei zu schreiben, die Ihr Makefile stattdessen ausführt?quelle
- Damit diese Antwort auch mit Python 3.x funktioniert ,
print
wird als Funktion aufgerufen : In 3.x funktioniert nurprint('foo')
, während 2.x auch akzeptiertprint 'foo'
.- Eine plattformübergreifende Perspektive mit Windows finden Sie in der hilfreichen Antwort von kxr .
In
bash
,ksh
oderzsh
:Verwenden Sie eine ANSI-Zeichenfolge mit C-Anführungszeichen (
$'...'
), mit\n
der Zeilenumbrüche dargestellt werden können, die zu tatsächlichen Zeilenumbrüchen erweitert werden, bevor die Zeichenfolge an Folgendes übergeben wirdpython
:Beachten Sie die Anweisungen
\n
zwischenimport
undfor
, um einen Zeilenumbruch zu bewirken.Um Shell-Variablenwerte an einen solchen Befehl zu übergeben, ist es am sichersten, Argumente zu verwenden und über
sys.argv
das Python-Skript darauf zuzugreifen :Im Folgenden finden Sie eine Erläuterung der Vor- und Nachteile der Verwendung einer (mit Escape-Sequenz vorverarbeiteten) Befehlszeichenfolge in doppelten Anführungszeichen mit eingebetteten Shell-Variablenreferenzen.
So arbeiten Sie sicher mit
$'...'
Saiten:\
Instanzen in Ihrem ursprünglichen Quellcode.\<char>
Sequenzen - wie\n
in diesem Fall, aber auch die üblichen Verdächtigen wie\t
,\r
,\b
- werden durch erweitert$'...'
(sieheman printf
für die unterstützten Fluchten)'
Instanzen als\'
.Wenn Sie POSIX-konform bleiben müssen :
Verwendung
printf
mit einer Befehlssubstitution :So arbeiten Sie sicher mit dieser Art von Zeichenfolge:
\
Instanzen in Ihrem ursprünglichen Quellcode.\<char>
Sequenzen - wie\n
in diesem Fall, aber auch die üblichen Verdächtigen wie\t
,\r
,\b
- durch erweitert werdenprintf
(sieheman printf
für die unterstützten Escape - Sequenzen).Übergeben Sie einen einfachen Anführungszeichen Zeichenfolge
printf %b
und entkommen eingebettete einfache Anführungszeichen als'\''
(sic).Die Verwendung von einfachen Anführungszeichen schützt den Inhalt der Zeichenfolge vor der Interpretation durch die Shell .
Für kurze Python-Skripte (wie in diesem Fall) können Sie jedoch eine Zeichenfolge in doppelten Anführungszeichen verwenden, um Shell- Variablenwerte in Ihre Skripte aufzunehmen - sofern Sie die damit verbundenen Fallstricke kennen (siehe nächster Punkt). Beispielsweise wird die Shell
$HOME
auf das Home-Verzeichnis des aktuellen Benutzers erweitert . im folgenden Befehl:python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")"
Der allgemein bevorzugte Ansatz besteht jedoch darin, Werte aus der Shell über Argumente zu übergeben und über
sys.argv
in Python darauf zuzugreifen . Das Äquivalent des obigen Befehls ist:python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
Die Verwendung einer Zeichenfolge in doppelten Anführungszeichen ist zwar bequemer - Sie können eingebettete einfache Anführungszeichen ohne Leerzeichen und eingebettete doppelte Anführungszeichen verwenden, da
\"
- die Zeichenfolge auch von der Shell interpretiert werden kann, was möglicherweise beabsichtigt ist oder nicht.$
und`
Zeichen im Quellcode, die nicht für die Schale gemeint können einen Syntaxfehler verursachen oder die Zeichenfolge unerwartet ändern.\
Verarbeitung der Shell in Zeichenfolgen in doppelten Anführungszeichen stören. Damit Python beispielsweise eine Literalausgabe erzeugtro\b
, müssen Siero\\b
diese übergeben. Mit einer'...'
Shell-Zeichenfolge und doppelten\
Instanzen erhalten wir:python -c "$(printf %b 'import sys\nprint("ro\\\\bs")')" # ok: 'ro\bs'
Im Gegensatz dazu funktioniert dies nicht wie beabsichtigt mit einer
"..."
Shell-Zeichenfolge:python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs'
Die Shell interpretiert beide
"\b"
und"\\b"
als Literal\b
und erfordert eine schwindelerregende Anzahl zusätzlicher\
Instanzen, um den gewünschten Effekt zu erzielen:python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"
Um den Code via zu passieren
stdin
anstatt-c
:Hinweis: Ich bin mit Schwerpunkt auf einzelne hier -Linie Lösungen; xorho Antwort zeigt , wie eine mehrzeilige verwenden , hier-Dokument - sicher sein , zu zitieren , das Trennzeichen, jedoch; Beispiel: Es
<<'EOF'
sei denn, Sie möchten ausdrücklich, dass die Shell die Zeichenfolge vorne erweitert (was mit den oben genannten Einschränkungen verbunden ist).In
bash
,ksh
oderzsh
:Kombinieren Sie eine ANSI C-Zeichenfolge (
$'...'
) mit einer Here-Zeichenfolge (<<<...
):-
weistpython
explizit an, von stdin zu lesen (was standardmäßig der Fall ist).-
ist in diesem Fall optional, aber wenn Sie auch Argumente an die Skripte übergeben möchten, benötigen Sie diese, um das Argument von einem Skriptdateinamen zu unterscheiden:Wenn Sie POSIX-konform bleiben müssen :
Verwenden Sie es
printf
wie oben, jedoch mit einer Pipeline , um die Ausgabe über stdin zu übergeben:Mit einem Argument:
quelle
Ihr Problem entsteht durch die Tatsache, dass Python-Anweisungen, die durch getrennt
;
sind, nur "kleine Anweisungen" sein dürfen, die alle Einzeiler sind. Aus der Grammatikdatei in den Python-Dokumenten :Zusammengesetzte Anweisungen können nicht über Semikolons in dieselbe Zeile mit anderen Anweisungen eingefügt werden. Daher ist es
-c
sehr unpraktisch , dies mit dem Flag zu tun .Wenn ich Python in einer Bash-Shell-Umgebung demonstriere, finde ich es sehr nützlich, zusammengesetzte Anweisungen einzuschließen. Die einzige einfache Möglichkeit, dies zuverlässig zu tun, sind Heredocs (eine Posix-Shell-Sache).
Heredocs
Verwenden Sie einen heredoc (erstellt mit
<<
) und der Python Kommandozeilen - Schnittstelle Option ,-
:Durch Hinzufügen von
-
after<<
(the<<-
) können Sie Tabulatoren zum Einrücken verwenden (Stackoverflow konvertiert Tabulatoren in Leerzeichen, daher habe ich 8 Leerzeichen eingerückt, um dies hervorzuheben). Die führenden Registerkarten werden entfernt.Sie können es ohne die Registerkarten mit nur tun
<<
:Das Setzen von Anführungszeichen
EOF
verhindert die Erweiterung von Parametern und Arithmetik . Dies macht den Heredoc robuster.Bash mehrzeilige Saiten
Wenn Sie doppelte Anführungszeichen verwenden, erhalten Sie eine Shell-Erweiterung:
Verwenden Sie einfache Anführungszeichen, um eine Shell-Erweiterung zu vermeiden:
Beachten Sie, dass wir die Anführungszeichen in den Literalen in Python austauschen müssen - wir können grundsätzlich keine Anführungszeichen verwenden, die von BASH interpretiert werden. Wir können sie zwar abwechseln, wie wir es in Python können - aber das sieht schon ziemlich verwirrend aus, weshalb ich dies nicht empfehle:
Kritik der akzeptierten Antwort (und anderer)
Dies ist nicht sehr gut lesbar:
Nicht sehr gut lesbar und im Fehlerfall zusätzlich schwer zu debuggen:
Vielleicht etwas lesbarer, aber immer noch ziemlich hässlich:
Sie werden eine schlechte Zeit haben, wenn Sie
"
in Ihrer Python haben:Missbrauche
map
oder liste kein Verständnis auf, um for-Schleifen zu erhalten:Diese sind alle traurig und schlecht. Tu sie nicht.
quelle
bash
,ksh
oderzsh
) ist eine vernünftige Lösung:python -c $'import sys\nfor r in range(10): print(\'rob\')'
(nur zur Sorge Apostrophe haben würde über Flucht (die man durch doppelte Anführungszeichen vermeiden kann) und Backslashes).Verwenden Sie einfach return und geben Sie es in die nächste Zeile ein:
quelle
python $(srcdir)/myscript.py
für große Gerechtigkeit.$ python2.6 -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"
Funktioniert gut. Verwenden Sie "[]", um Ihre for-Schleife zu inline.
quelle
Das Problem liegt nicht bei der
import
Aussage. Das Problem ist, dass die Kontrollflussanweisungen in einem Python-Befehl nicht inline funktionieren. Ersetzen Sie dieseimport
Anweisung durch eine andere Anweisung, und Sie werden das gleiche Problem sehen.Denken Sie darüber nach: Python kann unmöglich alles inline. Es verwendet Einrückungen, um den Kontrollfluss zu gruppieren.
quelle
Wenn Ihr System Posix.2-kompatibel ist, sollte es das folgende
printf
Dienstprogramm bereitstellen :quelle
printf %b '...' | python
für zusätzliche Robustheit zu verwenden, da sie verhindert, dassprintf
Sequenzen wie%d
(Formatbezeichner) in der Eingabezeichenfolge interpretiert werden . Sofern Sie nicht explizit Shell-Erweiterungen auf Ihre Python-Befehlszeichenfolge im Voraus anwenden möchten (was verwirrend sein kann), ist es besser,'
einfache Anführungszeichen für das äußere Anführungszeichen zu verwenden , um sowohl die Erweiterungen als auch die von der Shell angewendete Spielverarbeitung zu vermeiden zu Anführungszeichen in doppelten Anführungszeichen.single/double quotes
undbackslash
überall:Viel besser:
quelle
(antwortete am 23. November 10 um 19:48 Uhr ) Ich bin nicht wirklich ein großer Pythoner - aber ich habe diese Syntax einmal gefunden und vergessen, woher sie stammt, also dachte ich, ich würde sie dokumentieren:
Wenn Sie
sys.stdout.write
anstelle vonprint
( der Unterschied besteht darin, dasssys.stdout.write
Argumente als Funktion in Klammern verwendet werden - wohingegenprint
dies nicht der Fall ist ), können Sie bei einem Einzeiler die Reihenfolge des Befehls umkehren undfor
das Semikolon entfernen. und Einschließen des Befehls in eckige Klammern, dh:Habe keine Ahnung wie diese Syntax in Python heißen würde :)
Hoffe das hilft,
Prost!
(EDIT Di Apr 9 20:57:30 2013) Nun, ich glaube, ich habe endlich herausgefunden, worum es bei diesen eckigen Klammern in Einzeilern geht. sie sind "Listenverständnisse" (anscheinend); Beachten Sie dies zuerst in Python 2.7:
Der Befehl in runden Klammern / Klammern wird also als "Generatorobjekt" angesehen. Wenn wir es durch Aufrufen "durchlaufen", wird
next()
der Befehl in der Klammer ausgeführt (beachten Sie das "abc" in der Ausgabe):Wenn wir jetzt eckige Klammern verwenden, müssen Sie nicht aufrufen
next()
, damit der Befehl ausgeführt wird. Er wird sofort nach der Zuweisung ausgeführt. jedoch zeigt spätere Untersuchung , dassa
istNone
:Dies lässt nicht viele Informationen zu suchen, für den Fall der eckigen Klammern - aber ich bin auf diese Seite gestoßen, die meiner Meinung nach erklärt:
Python Tipps und Tricks - Erste Ausgabe - Python Tutorials | Dream.In.Code :
Und in der Tat ist es eine Liste - es ist nur das erste Element, das zu keinem wird, sobald es ausgeführt wird:
Listenverständnisse sind ansonsten in 5. Datenstrukturen: 5.1.4 dokumentiert . Listenverständnisse - Python v2.7.4-Dokumentation als "Listenverständnisse bieten eine übersichtliche Möglichkeit zum Erstellen von Listen"; vermutlich kommt hier die eingeschränkte "Ausführbarkeit" von Listen in Einzeilern ins Spiel.
Nun, ich hoffe, ich bin hier nicht zu daneben ...
EDIT2: und hier ist eine einzeilige Befehlszeile mit zwei nicht verschachtelten for-Schleifen; beide in eckigen Klammern "Listenverständnis" eingeschlossen:
Beachten Sie, dass die zweite "Liste"
b
jetzt zwei Elemente enthält, da ihre for-Schleife explizit zweimal ausgeführt wurde. Das Ergebnis von war jedochsys.stdout.write()
in beiden Fällen (anscheinend)None
.quelle
Diese Variante ist am portabelsten, um mehrzeilige Skripte unter Windows und * nix, py2 / 3, ohne Pipes in die Befehlszeile zu stellen:
(Keines der anderen hier gezeigten Beispiele hat dies bisher getan)
Ordentlich unter Windows ist:
Ordentlich auf bash / * nix ist:
Diese Funktion verwandelt jedes mehrzeilige Skript in einen tragbaren Befehls-Einzeiler:
Verwendung:
Eingabe war:
quelle
--%
vor dem Befehlszeichenfolgenargument einfügen .print "path is %%PATH%%"
resp.print "path is $PATH"
ist normalerweise die Option, die man in einem Skript oder einer Befehlszeile haben möchte - es sei denn, man entgeht den für die Plattform üblichen Dingen. Gleiches gilt für andere Sprachen. (Die Python-Syntax selbst schlägt nicht regelmäßig die Verwendung von% und $ in konkurrierender Weise vor.)$foo
in Ihrem Python-Code benötigen ? Wenn Sie es\$foo
zugunsten von POSIX-ähnlichen Shells entkommen, sehen Siecmd.exe
immer noch das Extra\
. Es mag selten sein, aber es lohnt sich zu wissen.Dieses Skript bietet eine Perl-ähnliche Befehlszeilenschnittstelle:
Pyliner - Skript zum Ausführen von beliebigem Python-Code in der Befehlszeile (Python-Rezept)
quelle
Wenn ich das tun musste, benutze ich
Beachten Sie den dreifachen Backslash für den Zeilenumbruch in der Anweisung sys.stdout.write.
quelle
echo -e
, was nicht dem Standard entspricht und erfordertbash
,ksh
oderzsh
Sie können auch eine$'...'
Zeichenfolge direkt verwenden, was auch daspython -c $'import sys\nsys.stdout.write("Hello World!\\n")'
Ich wollte eine Lösung mit folgenden Eigenschaften:
Beide Anforderungen wurden in den anderen Antworten nicht angegeben. So lesen Sie stdin, während Sie alles in der Befehlszeile ausführen:
quelle
Es gibt noch eine weitere Option: sys.stdout.write gibt None zurück, wodurch die Liste leer bleibt
quelle
Wenn Sie stdin nicht berühren und simulieren möchten, als hätten Sie "python cmdfile.py" übergeben, können Sie mit einer Bash-Shell Folgendes tun:
Wie Sie sehen können, können Sie stdin zum Lesen von Eingabedaten verwenden. Intern erstellt die Shell die temporäre Datei für den Inhalt des Eingabebefehls.
quelle
-c "$(...)"
es dasselbe tut und POSIX-kompatibel ist); um dem<(...)
Konstrukt einen Namen zu geben : Prozesssubstitution ; es funktioniert auch inksh
undzsh
.