Welcome, guest | Sign In | My Account | Store | Cart

Generate a Windows command file that executes a Python program. Typing 'my_prog arg1 is easier than typing 'python C:\PyLib\my_prog.py arg1'. Needed because Windows does not support '#!/bin/env python' as the first line of the program.

Python, 63 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# MkPyCmd.py
# Copyright 2005 by James M Jinkins --- Released to the Public Domain.
# email address: jim -dot_ jinkins -at_ comports -dot_ com

progDoc = r"""MkPyCmd.py generates a command file to execute a Python program.

The windows command file will have the same filename as the Python program, but 
will have a '.cmd' extension instead of '.py..  It will pass its command line 
arguments to the Python program.

Note:

usage:      python [py_path\]python_program [cmd_path]
  where
    py_path         Optional path to the python program.  Default is the
                    current directory.  
    python_program  Python program.  Since the extension must be .py,
                    it is not required.
    cmd_path        Optional path to the generated command file.  Default is 
                    the current directory.  Generate it in a directory in the 
                    PATH environment variable.
The command
    python C:\PyLib\MkPyCmd.py C:\PyLib\my_prog C:\cmd
generates file C:\cmd\my_prog.cmd, which contains this line:
    python "C:\PyLib\my_prog.py" %*
"""

import os
import sys

def displayErrMsgExit(msg = ''):
    print progDoc
    if msg:
        print "\nError: %s" % msg
    sys.exit(1)


if (len(sys.argv) < 2 or sys.argv[1].lower() == '-h' or 
        sys.argv[1].lower() == '--help'): 
    displayErrMsgExit()
if len(sys.argv) > 3:
    displayErrMsgExit("Too many command line arguments")
pyProgram = sys.argv[1]
pyProgPath = os.path.abspath(pyProgram) 
pyPath, pyFilespec = os.path.split(pyProgPath)
pyFilename, pyExt = os.path.splitext(pyFilespec)
if pyExt.lower() == '.py':
    cmdFilespec = pyFilename + '.cmd'
else:
    cmdFilespec = pyFilespec + '.cmd'
    pyProgPath += '.py'
if not os.path.isfile(pyProgPath):
    displayErrMsgExit("python_program file '%s' not found" % pyProgramPath)
if len(sys.argv) > 2:
    if not os.path.isdir(sys.argv[2]):
        displayErrMsgExit("cmd_path arg '%s' is not a directory" % 
                sys.argv[2])
    cmdPath = os.path.join(sys.argv[2], cmdFilespec)
else:
    cmdPath = cmdFilespec
f = open(cmdPath, 'w')
print >>f, 'python "%s" %%*' % pyProgPath 
f.close()

When I write a Python program command with a command-line interface for my own use on Windows and especially for non-Python-programmers, I usually wrap it in a command file with the same filename. Then, instead of typing python C:\PyLib\my_prog.py arg1 ... I type my_prog arg1 ...

I finally got tired of manually writing each command file and wrote MkPyCmd.py. Then I ran it to generate MkPyCmd.cmd in a directory on the PATH.

9 comments

Martin Miller 19 years, 2 months ago  # | flag

Simpler Way? Perhaps I don't fully understand what the purpose or effects of this recipe -- but the best way I've found to accompish something similar is to modify your PATHEXT environment variable to include .py files. Then you can just enter the name of the .py file at the command line (with or without the '.py' extension), and it will treat it as an executable.

On Win XP Pro you can modify the PATHEXT environment variable by clicking the Environment Variables button on the Advanced tab in My Computer's properties dialog (or via the 'System' Control Panel).

Steve Lucy 19 years, 2 months ago  # | flag

Even simpler... I use ActiveState's ActivePython distribution and this is handled automatically for me on Windows by the installation. All I have to do to run a python file called 'something.py' is type 'something' or 'something.py', followed by any other arguments.

Vivian De Smedt 19 years, 2 months ago  # | flag

I agree but. I agree with you. However, up to my knowledge, there is still some case where a .cmd wrapper could be usefull.

If you plan to redirect the input of your script the pathext trick seems not adequate and the .cmd yes.

my_prog.py &lt; new_input.txt > new_output.txt

is not the same as:

C:\Python24\Python.exe my_prog.py &lt; new_input.txt > new_output.txt

that could be wrapped into:

my_prog.cmd &lt; new_input.txt > new_output.txt
Harald Armin massa 19 years, 2 months ago  # | flag

it is possible to do it MUCH shorter.

1) rename the file.py to file.cmd
2) insert the following code into line 1
@python -x %~f0 %* <pre>1) rename the file.py to file.cmd
2) insert the following code into line 1
@python -x %~f0 %*

</pre>

Harald Armin massa 19 years, 2 months ago  # | flag

and the 2 lines that zope did cut. 3) be sure that python is within your path

4) enjoy

Harald Armin Massa

(I do not take credit for this, I googled it up some loooong time ago, pls do not ask where; I assume "unfrequently asked questions")

Tim Lesher 19 years, 2 months ago  # | flag

Need to add one bit... As written, cmd.exe will run the python script, then continue trying to interpret the rest of the .cmd file as batch commands. To prevent this, use this header instead:

@python -x %~f0 %* &amp; exit /b

A few notes:

  • The single ampersand ("&") means that the "exit /b" clause runs no matter what the python script returns as an exit code; the more commonly-used "&&" will not run the exit clause if the python script ends with a nonzero return code.

  • The /b on exit means "exit the current batchfile"; without /b, the instance of cmd.exe will exit.

Harald Armin massa 19 years, 2 months ago  # | flag

correct... Tim, you are more than correct.

Cutting and Pasting failed, orginally there was:

goto :EOF

added, but I could not get it through the filters :((

Vivian De Smedt 19 years, 2 months ago  # | flag
@python -x "%~f0" %* &amp; exit /b

I had to add quotes to deal with scripts that are in folder with spaces in they pathname. I'am glad of this receipt it works perfectly redirecting input and output the right way and returning the right return code. Apart from the fact that it isn't platform dependent it is wondefull ;-).

Tim Lesher 19 years, 2 months ago  # | flag

Ahh... I saw that when I previewed my post as well... it's not a question of filters; ASPN's site doesn't properly escape certain characters. If you want an ampersand, you have to escape it yourself, HTML-style, using &amp;