16

I have the canonical shebang at the top of my python scripts.

#!/usr/bin/env python

However, I still often want to export unbuffered output to a log file when I run my scripts, so I end up calling:

$ python -u myscript.py &> myscript.out &

Can I embed the -u option in the shebang like so...

#!/usr/bin/env python -u

and only call:

$ ./myscript.py &> myscript.out &

...to still get the unbuffering? I suspect that won't work, and want to check before trying. Is there something that would accomplish this?

Mittenchops
  • 18,633
  • 33
  • 128
  • 246
  • Yes, you should. The "shebang" is just a pointer to the binary application in charge of the script. If not you can create a alias `alias ppython="python -u"` and just use `#!/usr/bin/env ppython` – Torxed May 14 '13 at 17:34
  • 2
    Torxed, did you try your answer? That approach doesn't work in OSX or Linux. If it works in your OS, please share the details since that would be interesting. The reason it doesn't work in OSX or Linux (or I would believe, any flavor of unix) is that `env` searches for an executable on the path, and aliases are not on the path. Aliases don't work on the shebang line in the same way and for the same reason that built-ins don't work on the shebang line. If your OS allows this, please share! – Chris Johnson Nov 21 '15 at 03:38

3 Answers3

14

You can have arguments on the shebang line, but most operating systems have a very small limit on the number of arguments. POSIX only requires that one argument be supported, and this is common, including Linux.

Since you're using the /usr/bin/env command, you're already using up that one argument with python, so you can't add another argument -u. If you want to use python -u, you'll need to hard-code the absolute path to python instead of using /usr/bin/env, e.g.

#!/usr/bin/python -u

See this related question: How to use multiple arguments with a shebang (i.e. #!)?

Community
  • 1
  • 1
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks. It looked easy enough, but I knew there'd be a catch. =) Is there someone deep in the bowels of POSIX requirements I can send an email to talking about how great this feature would be if it were possible to support more than one argument? – Mittenchops May 23 '13 at 14:26
  • 3
    Probably not. This is how it has always worked, and POSIX simply standardized existing behavior. Even if they changed POSIX, you'd have to wait years for enough implementations to be redesigned so you could use it portably. – Barmar May 23 '13 at 15:34
6

In new versions of env since coreutils 8.30 there is option -S for this. Citation from man env:

   The -S option allows specifing multiple parameters in a script.  Running a script named 1.pl containing the follow‐
  ing first line:

         #!/usr/bin/env -S perl -w -T

  Will execute perl -w -T 1.pl .

  Without the '-S' parameter the script will likely fail with:

         /usr/bin/env: 'perl -w -T': No such file or directory
user3132194
  • 2,381
  • 23
  • 17
4

A portable way to do this is to create another executable that embodies your options.

For example, put this file on your path and name it upython, and make it executable:

#!/usr/bin/env bash
python -u -and -other -options "$@"

... using whatever options you need. Then your myscript.py script can be like this:

#!/usr/bin/env upython
(... your normal Python code ...)

Torxed suggested doing this via a shell alias. I'd be very surprised if that worked in any version of unix. It doesn't work in the few distributions I just tested. My approach will work in any unix.

Chris Johnson
  • 20,650
  • 6
  • 81
  • 80
  • ps: and the proper way to pass cmdline args to another script or function is using a quoted `"$@"` (vs just `$@`), since without the quotes, args with spaces would get broken up. (And the bit here about aliases is absolutely correct. It won't work.) Lastly, I'd recommend never using `env bash`, but rather using the path to `bash` (e.g., `#!/bin/bash`) directly. Python is problematic, to be sure. Bash, not so much. The greater problem w/ bash is in fact accidentally using the wrong one, after tweaking the `PATH` to use different other tools (python, make, etc). – michael Aug 10 '16 at 07:07
  • For wrapper scripts like this, I like putting in "exec" so the wrapper no longer appears in the process list. I.e., "exec python -u -and -other ...." – Chris Cogdon Nov 23 '17 at 23:56