Mit "#! / Usr / bin / env python" kann kein Argument an Python übergeben werden.


76

Ich brauchte ein direkt ausführbares Python-Skript, also startete ich die Datei mit #!/usr/bin/env python. Allerdings brauche ich auch ungepufferte Ausgabe, also habe ich es versucht #!/usr/bin/env python -u, aber das schlägt fehl python -u: no such file or directory.

Ich fand , dass heraus #/usr/bin/python -ufunktioniert, aber ich brauche es die zu bekommen pythonin PATHvirtuellen zu unterstützen envUmgebungen.

Was sind meine Optionen?


1
In dieser SO-Frage finden Sie einige Informationen zur ungepufferten Ausgabe.
Mattias Nilsson

Antworten:



43

In einigen Umgebungen teilt env keine Argumente auf. Also sucht deine Umgebung python -uauf deinem Weg. Wir können sh verwenden, um herumzuarbeiten. Ersetzen Sie Ihren Shebang durch die folgenden Codezeilen und alles wird gut.

#!/bin/sh
''''exec python -u -- "$0" ${1+"$@"} # '''
# vi: syntax=python

ps wir brauchen uns keine sorgen um den weg zu sh, oder?


2
Für diejenigen, die sich fragen, wie das funktioniert: Warum funktioniert dieses Snippet?
Martijn Pieters

14
Der ${1+"$@"}Hack war wahrscheinlich seit mindestens 20 Jahren unnötig :)
user4815162342

2
Der Hack ist vielleicht unnötig, aber er schadet nicht, oder? Es macht Spaß, davon zu wissen :-) Ich habe heute gerade davon erfahren. Wie auch immer, ich denke, es ist "exec" "python" "-u" "--" "$0" "$@"vielleicht einfacher zu verstehen - gibt es einen Fehler darin? (Ich denke, es ist nicht kompatibel mit dem 1+Hack?)
Aaron McDaid

1
Meine Methode hat einen Nachteil. Wenn Sie etwas Kompliziertes zum Bash übergeben möchten, z. B. eine Zeichenfolge mit verschachteltem 'oder ", ist Ihre Methode zuverlässiger. Es ist ein interessantes Thema! Meins ist vielleicht leichter zu verstehen, aber deins ist robuster. Vielleicht sollte Ihre Antwort klarstellen, dass sie mit beginnen muss ''''execund die Zeichenfolge # '''mit (mit einem Leerzeichen vor dem #) enden muss . Solange wir diese Regeln befolgen und keine zusätzlichen Anführungszeichen haben ''', ist Ihre Methode perfekt und flexibel.
Aaron McDaid

1
@ user4815162342 Hier ist mehr Kontext auf ${1+"$@"}. Sollte also "$@"in den meisten Fällen von alleine gut funktionieren.
Akhan

16

Wenn Sie shebang unter Linux verwenden, wird der gesamte Rest der Zeile nach dem Interpreternamen als einzelnes Argument interpretiert. Das python -uwird an übergeben, envals ob Sie Folgendes eingegeben hätten : /usr/bin/env 'python -u'. Die /usr/bin/envSuche nach einer Binärdatei namens python -u, die es keine gibt.


13

Das Übergeben von Argumenten an die Shebang-Zeile ist nicht Standard und funktioniert, wie Sie experimentiert haben, unter Linux nicht in Kombination mit env. Die Lösung mit bash besteht darin, den eingebauten Befehl "set" zu verwenden, um die erforderlichen Optionen festzulegen. Ich denke, Sie können das Gleiche tun, um die ungepufferte Ausgabe von stdin mit einem Python-Befehl festzulegen.

my2c


13

Dies mag etwas veraltet sein, aber das Handbuch env (1) sagt, dass man für diesen Fall '-S' verwenden kann

#!/usr/bin/env -S python -u

Es scheint ziemlich gut auf FreeBSD zu funktionieren.


Wow, es wäre gut, wenn dies weit verbreitet wäre, aber auch nicht auf Cygwin verfügbar ist :(
Philwalk

6
Scheint, als ob die -SOption spezifisch für die BSD-Variante von ist, env(1)aber es ist gut zu wissen
nodakai

3
Linux hat env -Sjetzt auch - ab Coreutils 8.30 1 (es kann eine Weile dauern, bis es in einer Distribution in Ihrer Nähe erscheint). Gleiche Semantik wie bei FreeBSD env(1)- Hurra für die Portabilität guter Funktionen.
Juan

Auch auf Solaris (11.3) kein Glück ... :(
Timmah

9

Hier ist eine Skriptalternative zu /usr/bin/env, die die Übergabe von Argumenten in der Hash-Bang-Zeile ermöglicht, basierend auf /bin/bashund mit der Einschränkung, dass Leerzeichen im ausführbaren Pfad nicht zulässig sind. Ich nenne es "envns" (env No Spaces):

#!/bin/bash

ARGS=( $1 )  # separate $1 into multiple space-delimited arguments.
shift # consume $1

PROG=`which ${ARGS[0]}`
unset ARGS[0] # discard executable name

ARGS+=( "$@" ) # remainder of arguments preserved "as-is".
exec $PROG "${ARGS[@]}"

Angenommen, dieses Skript befindet sich unter / usr / local / bin / envns, dann ist hier Ihre Shebang-Zeile:

#!/usr/local/bin/envns python -u

Getestet auf Ubuntu 13.10 und Cygwin x64.


2
Dies sollte gebündelt werden :)
wieczorek1990

Hinweis: Die meisten Unix-ish #! Implementierungen erlauben aus Sicherheitsgründen nicht die Verwendung von Skripten. Ich bin überrascht, dass dies unter Ubunut 13.10 funktioniert hat.
Juan

funktioniert auch auf Ubuntu 16.04 ab 2019-01-20, nicht sicher über andere.
Philwalk

5

Dies ist ein Kludge und erfordert Bash, aber es funktioniert:

#!/bin/bash

python -u <(cat <<"EOF"
# Your script here
print "Hello world"
EOF
)

1
Vielen Dank, dies funktionierte gut für mich für ein anderes Problem (mit der Mono-Csharp-Shell mit Argumenten)
IanNorton

5

Aufbauend auf Larry Cais Antwort envkönnen Sie eine Variable direkt in der Befehlszeile festlegen. Das bedeutet, dass -udies durch die entsprechende PYTHONUNBUFFEREDEinstellung vor ersetzt werden kann python:

#!/usr/bin/env PYTHONUNBUFFERED="YESSSSS" python

Funktioniert mit RHEL 6.5. Ich bin mir ziemlich sicher, dass diese Funktion envnahezu universell ist.


3
Zu Ihrer Information, dies funktioniert NICHT in Debian. Ich bin mir nicht sicher, warum es nicht funktioniert (um die psAusgabe zu betrachten, sollte es keinen Unterschied geben), aber es kehrt nie zurück. Es ist nicht sehr klar, ob Python selbst überhaupt läuft, wenn Sie dies in Debian tun. Ich habe dies an einigen Stellen versucht - funktioniert definitiv nicht wie erwartet im Vergleich zur entsprechenden Befehlszeile.
MartyMacGyver

@ MartinMacGyver. Sehr wahrscheinlich mit der Version von envoder sogar pythonSie verwenden.
Mad Physicist

Könnte die Version von env sein, funktioniert aber bisher mit keiner modernen Debian-Variante. Es scheint nicht, dass Python tatsächlich in diesem Szenario unter Debian ausgeführt wird, sodass es außerhalb bestimmter Plattformen und / oder Konfigurationen nur eingeschränkt verwendet werden kann.
MartyMacGyver

-1

Ich habe kürzlich einen Patch für die GNU Coreutils-Version von geschrieben env, um dieses Problem zu beheben :

http://lists.gnu.org/archive/html/coreutils/2017-05/msg00018.html

Wenn Sie dies haben, können Sie tun:

#!/usr/bin/env :lang:--foo:bar

envwird :lang:foo:--barin die Felder aufgeteilt lang, foound --bar. Es sucht PATHfür den Dolmetscher lang, und dann rufen Sie es mit Argumenten --foo, barsowie der Pfad zum Skript und das Skript Argumente.

Es gibt auch eine Funktion, mit der Sie den Namen des Skripts in der Mitte der Optionen übergeben können. Angenommen, Sie möchten ausführen lang -f <thecriptname> other-arg, gefolgt von den verbleibenden Argumenten. Mit diesem Patch envwird es folgendermaßen gemacht:

#!/usr/bin/env :lang:-f:{}:other-arg

Das Feld ganz links, das äquivalent ist, {}wird durch das erste folgende Argument ersetzt, das unter Hash-Bang-Aufruf der Skriptname ist. Dieses Argument wird dann entfernt.

Hier other-argkönnte etwas von langoder vielleicht etwas von dem Skript verarbeitet werden.

Weitere Informationen finden Sie in den zahlreichen echoTestfällen im Patch.

Ich habe das :Zeichen gewählt, weil es ein vorhandenes Trennzeichen ist, das PATHauf POSIX-Systemen verwendet wird. Da envdie PATHSuche durchgeführt wird, ist es offensichtlich unwahrscheinlich, dass sie für ein Programm verwendet wird, dessen Name einen Doppelpunkt enthält. Die {}Markierung stammt vom findDienstprogramm, mit dem das Einfügen eines Pfads in die -execBefehlszeile bezeichnet wird.


1
Für jeden, der dies liest und sich hoffnungsvoll fühlt, wurde der Patch aufgegeben .
Alex Miller
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.