How do I find a file that may not be fully-qualified by using the environment path?
Asked Answered
G

6

11

I have an executable name, like cmd.exe and need to resolve its fully-qualified path. I know the exe appears in one of the directories listed in the PATH environment variable. Is there a way to resolve the full path without parsing and testing each directory in the PATH variable? Basically I don't want to do this:

foreach (string entry in Environment.GetEnvironmentVariable("PATH").Split(';'))
    ...

There has to be a better way, right?

Googol answered 15/9, 2009 at 21:7 Comment(0)
H
2

This seems like a pretty good way of doing it already -- as far as I know, searching through the directories in the PATH environment variable is what Windows does anyway when it's trying to resolve a path.

Headroom answered 15/9, 2009 at 21:21 Comment(0)
F
14

Here's another approach:

string exe = "cmd.exe";
string result = Environment.GetEnvironmentVariable("PATH")
    .Split(';')
    .Where(s => File.Exists(Path.Combine(s, exe)))
    .FirstOrDefault();

Result: C:\WINDOWS\system32

The Path.Combine() call is used to handle paths that don't end with a trailing slash. This will properly concatenate the strings to be used by the File.Exists() method.

Fran answered 15/9, 2009 at 21:27 Comment(0)
D
5

You could Linq it with

string path = Environment
                .GetEnvironmentVariable("PATH")
                .Split(';')
                .FirstOrDefault(p => File.Exists(p + filename));

A little more readable maybe?

Dan

Dovecote answered 15/9, 2009 at 21:28 Comment(3)
I believe you need to correctly construct the path before you can call File.Exists. File.Exists(Path.Combine(p, filename))Boulogne
I can confirm this did not work for me.Progestin
In case you care about X-plat, you should also replace ';' with System.IO.Path.PathSeparator. ';' is for Windows NT PATHs, whereas the rest of the world uses ':'.Sporogony
G
4

Well, I did find the following; however, I think I'll stick to the managed implementation.

static class Win32
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = false)]
    static extern bool PathFindOnPath([MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszFile, IntPtr unused);

    public static bool FindInPath(String pszFile, out String fullPath)
    {
        const int MAX_PATH = 260;
        StringBuilder sb = new StringBuilder(pszFile, MAX_PATH);
        bool found = PathFindOnPath(sb, IntPtr.Zero);
        fullPath = found ? sb.ToString() : null;
        return found;
    }
}
Googol answered 15/9, 2009 at 22:6 Comment(0)
H
2

This seems like a pretty good way of doing it already -- as far as I know, searching through the directories in the PATH environment variable is what Windows does anyway when it's trying to resolve a path.

Headroom answered 15/9, 2009 at 21:21 Comment(0)
M
1

I ended up writing this function:

private static string GetExecutablePath(string executableFileName)
{
    var path = Environment
        .GetEnvironmentVariable("PATH")!
        .Split(';')
        .Select(s => Path.Combine(s, executableFileName))
        .FirstOrDefault(x => File.Exists(x));
    if (path == null)
    {
        throw new Exception($"Cannot find {executableFileName}. Is it installed on your computer?");
    }
    return path;
}

In my case, I wanted to find the path to python.exe, so I call the function like this:

GetExecutablePath("python.exe")

Which in my case returns:

"C:\\Program Files\\Python39\\python.exe"
Millardmillboard answered 14/7, 2022 at 9:21 Comment(0)
S
0

Couple of notes adding onto existing answers here, specifically regarding making a more platform-agnostic approach:

  • Split by System.IO.Path.PathSeparator. This resolves to ';' on Windows and ':' on pretty much anything else.
    • Also recommend passing StringSplitOptions.RemoveEmptyEntries, to avoid potential edge cases.
  • Check for the executable with and without the extension .exe.
  • Unfortunately, things invariably get messy (less readable) if you have to deal with cross platform support. Sorry.
Sporogony answered 2/10, 2023 at 16:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.