Cannot pass an argument to python with "#!/usr/bin/env python"

26,574

Solution 1

It is better to use environment variable to enable this. See python doc : http://docs.python.org/2/using/cmdline.html

for your case:

export PYTHONUNBUFFERED=1
script.py

Solution 2

In some environment, env doesn't split arguments. So your env is looking for python -u in your path. We can use sh to work around. Replace your shebang with the following code lines and everything will be fine.

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

p.s. we need not worry about the path to sh, right?

Solution 3

This might be a little bit outdated but env(1) manual tells one can use '-S' for that case

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

It seems to work pretty good on FreeBSD.

Solution 4

When you use shebang on Linux, the entire rest of the line after the interpreter name is interpreted as a single argument. The python -u gets passed to env as if you'd typed: /usr/bin/env 'python -u'. The /usr/bin/env searches for a binary called python -u, which there isn't one.

Solution 5

Passing arguments to the shebang line is not standard and in as you have experimented do not work in combination with env in Linux. The solution with bash is to use the builtin command "set" to set the required options. I think you can do the same to set unbuffered output of stdin with a python command.

my2c

Share:
26,574
Eskil
Author by

Eskil

Updated on July 08, 2022

Comments

  • Eskil
    Eskil almost 2 years

    I needed to have a directly executable python script, so i started the file with #!/usr/bin/env python. However, I also need unbuffered output, so i tried #!/usr/bin/env python -u, but that fails with python -u: no such file or directory.

    I found out that #/usr/bin/python -u works, but I need it to get the python in PATH to support virtual env environments.

    What are my options?

  • IanNorton
    IanNorton about 12 years
    Thanks, this worked well for me for another problem ( using the mono csharp shell with arguments )
  • Martijn Pieters
    Martijn Pieters almost 11 years
    For those wondering how this works: Why does this snippet work?
  • user4815162342
    user4815162342 over 10 years
    the ${1+"$@"} hack has probably been unnecessary for at least 20 years :)
  • Ade YU
    Ade YU over 10 years
    @user4815162342 Thank you for the information. I'll try "$@" next time. :)
  • Aaron McDaid
    Aaron McDaid almost 10 years
    The hack is unnecessary perhaps, but it doesn't do any harm does it? It's fun to know about it :-) I just learned about it today. Anyway, I think "exec" "python" "-u" "--" "$0" "$@" might be easier to understand - is there any flaw in it? (I think it's not compatible with the 1+ hack?)
  • Ade YU
    Ade YU over 9 years
    @AaronMcDaid Since the hack is unnecessary, your version works fine and is really much more readable! Great!
  • Aaron McDaid
    Aaron McDaid over 9 years
    There is a disadvantage with my method. If you want to pass something complicated to bash, such as a string with nested ' or ", then your method is more reliable. It's an interesting issue! Mine is easier to understand perhaps, but yours is more robust. Perhaps your answer should clarify that it must start with ''''exec, and the string must end in # ''' (with a space before the #). As long as we follow those rules, and don't have any extra triple-quotes ''', your method is perfect and flexible.
  • wieczorek1990
    wieczorek1990 over 9 years
    This should be bundled :)
  • philwalk
    philwalk over 8 years
    wow, it would be good if this worked widely, but also not available on cygwin :(
  • nodakai
    nodakai over 8 years
    Seems like the -S option is specific to BSD variant of env(1) but it's good to know
  • MartyMacGyver
    MartyMacGyver almost 8 years
    FYI, this does NOT work in Debian. I'm not sure why it doesn't work (to look at ps output there shouldn't be any difference) but it never returns. It's not very clear if python itself is actually running at all when you do this in Debian. I tried this in a few places - definitely doesn't work as expected versus the equivalent command line.
  • Mad Physicist
    Mad Physicist almost 8 years
    @MartyMacGyver. Very likely to do with the version of env or even python you are using.
  • MartyMacGyver
    MartyMacGyver almost 8 years
    Could be the version of env, but it's not working with any modern Debian variant thus far. It doesn't appear that Python is actually running in this scenario on Debian, making it of limited use outside certain platforms and/or configs.
  • Vladyslav Savchenko
    Vladyslav Savchenko almost 8 years
    Unfortunately this way conflicts with module's docstring. Is there any way to separate that hack and module's docstring?
  • Alex Miller
    Alex Miller almost 7 years
    To anyone reading this and feeling hopeful, the patch was abandoned.
  • akhan
    akhan over 6 years
    @user4815162342 Here is more context on ${1+"$@"}. So "$@" should work fine on its own in most cases.
  • akhan
    akhan almost 6 years
    So in summary, this trick is using python's module doc string to run a mini shell script first.
  • Juan
    Juan over 5 years
    Linux has env -S now, too - as of coreutils 8.30 1 (which may take a while to appear on a distro near you). Same semantics as FreeBSD's env(1) - hooray for portability of good features.
  • Juan
    Juan over 5 years
    Note: Most unix-ish #! implementations do not allow scripts to be used for security reasons. I'm surprised this worked on Ubunut 13.10.
  • philwalk
    philwalk over 5 years
    also works on ubuntu 16.04 as of 2019-01-20, not sure about others.
  • Timmah
    Timmah over 5 years
    No luck on Solaris (11.3) either... :(
  • dan
    dan over 4 years
    Do you need to do this on every restart?
  • artu-hnrq
    artu-hnrq about 3 years
    @dan: Not while you keep in same shell. After export a variable it will keep set until you overwrite or unset it
  • Dariusz Filipiak
    Dariusz Filipiak about 3 years
    #!/usr/bin/env -S node --inspect - WORKS!