13
import subprocess

proc = subprocess.Popen('git status')
print 'result: ', proc.communicate()

I have git in my system path, but when I run subprocess like this I get:
WindowsError: [Error 2] The system cannot find the file specified

How can I get subprocess to find git in the system path?

Python 2.6 on Windows XP.

2
  • The real problem isn't that subprocess isn't using PATH, but that git is installed as 'git.cmd', rather than 'git.exe', which would be found by subprocess.Popen. Commented May 11, 2012 at 16:24
  • This occurred for me using subprocess.check_output(...) on windows 10 after updating git to 2.19.1. Worked before the update. Now does not even work with shell=True. Commented Dec 11, 2018 at 16:07

4 Answers 4

12

The problem you see here is that the Windows API function CreateProcess, used by subprocess under the hood, doesn't auto-resolve other executable extensions than .exe. On Windows, the 'git' command is really installed as git.cmd. Therefore, you should modify your example to explicitly invoke git.cmd:

import subprocess

proc = subprocess.Popen('git.cmd status')
print 'result: ', proc.communicate()

The reason git works when shell==True is that the Windows shell auto-resolves git to git.cmd.

Eventually, resolve git.cmd yourself:

import subprocess
import os.path

def resolve_path(executable):
    if os.path.sep in executable:
        raise ValueError("Invalid filename: %s" % executable)

    path = os.environ.get("PATH", "").split(os.pathsep)
    # PATHEXT tells us which extensions an executable may have
    path_exts = os.environ.get("PATHEXT", ".exe;.bat;.cmd").split(";")
    has_ext = os.path.splitext(executable)[1] in path_exts
    if not has_ext:
        exts = path_exts
    else:
        # Don't try to append any extensions
        exts = [""]

    for d in path:
        try:
            for ext in exts:
                exepath = os.path.join(d, executable + ext)
                if os.access(exepath, os.X_OK):
                    return exepath
        except OSError:
            pass

    return None

git = resolve_path("git")
proc = subprocess.Popen('{0} status'.format(git))
print 'result: ', proc.communicate()
Sign up to request clarification or add additional context in comments.

3 Comments

Oh, ok. I'm not using Windows anymore, so I can't confirm this answer, but I'm just going to assume you're right. Thanks.
Also check [this python bug report][1]. [1]: bugs.python.org/issue17023 "If you add a directory into PATH on Windows so that the directory is in quotes, subprocess does not find executables in it."
The environment variable that lists executable extensions is called PATHEXT, not PATHEXTS. (The code as given will always fall back to ".exe;.bat;.cmd", since PATHEXTS typically won't exist.)
0

You mean

proc = subprocess.Popen(["git", "status"], stdout=subprocess.PIPE)

The first argument of subprocess.Popen takes a shlex.split-like list of arguments.

or:

proc = subprocess.Popen("git status", stdout=subprocess.PIPE, shell=True)

This is not recommended, as you are launching a shell then launching a process in the shell.

Also, you should use stdout=subprocess.PIPE to retrieve the result.

9 Comments

No, Popen takes either a string or a list. See docs.python.org/library/subprocess.html
Depends -- if you have arguments, then you must use a list. Otherwise, you're just invoking "git status" and not git status.
shell=True is required if you do not use a list of arguments.
Oh lordy, you do indeed need shell=True if you're on Windows, maybe. See bugs.python.org/issue8557 . The discussion in the comments is enlightening,
The reason that shell invocation works is simply that the shell auto-resolves 'git' against 'git.cmd', not just 'git.exe' like the Windows API does.
|
0

Note that in 2020, with With Git 2.28 (Q3 2020), Python 2.6 or older is no longer supported.

See commit 45a87a8 (07 Jun 2020) by Denton Liu (Denton-L).
(Merged by Junio C Hamano -- gitster -- in commit 6361eb7, 18 Jun 2020)

CodingGuidelines: specify Python 2.7 is the oldest version

Signed-off-by: Denton Liu

In 0b4396f068 ("git-p4: make python2.7 the oldest supported version", 2019-12-13, Git v2.27.0-rc0 -- merge listed in batch #1), git-p4 was updated to only support 2.7 and newer. Since Python 2.6 is pretty much ancient history, update CodingGuidelines to show that 2.7 is the oldest version supported.

Comments

-2

I believe you need to pass env in to Popen, something like:

import subprocess, os
proc = subprocess.Popen('git status', env=os.environ, stdout=subprocess.PIPE)

Should do the trick.

1 Comment

The default env is equivalent to os.environ.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.