Colonel Panic
Colonel Panic

Reputation: 137524

Get path to executable from command (as cmd does)

Given a command-line style path to a command such as bin/server.exe or ping, how can I get the full path to this executable (as cmd or Process.Start would resolve it)?

I tried Path.GetFullPath, but it always expands relative to the working directory. It expands bin/server.exe correctly, however given ping it returns c:\users\matt\ping (non-existent). I want c:\Windows\system32\ping.exe.

Edit: I would like the same behaviour as cmd. Some considerations:

  1. When there is a local executable with the same name as one in the path, cmd prefers the local one
  2. cmd can expand the command server to server.bat or server.exe (adding the file extension)

I also tried Windows' command-line tool called where . It does almost I want:

Displays the location of files that match the search pattern. By default, the search is done along the current directory and in the paths specified by the PATH environment variable.

>where ping
C:\Windows\System32\PING.EXE
>where bin\server
INFO: Could not find files for the given pattern(s).

(This question is hard to search around because of the two different meanings of the word 'path')

Upvotes: 11

Views: 11033

Answers (5)

Rup
Rup

Reputation: 34408

Considering PATHEXT too, stealing from Serj-Tm's answer (sorry! +1 to him):

public static string WhereSearch(string filename)
{
    var paths = new[]{ Environment.CurrentDirectory }
            .Concat(Environment.GetEnvironmentVariable("PATH").Split(';'));
    var extensions = new[]{ String.Empty }
            .Concat(Environment.GetEnvironmentVariable("PATHEXT").Split(';')
                       .Where(e => e.StartsWith(".")));
    var combinations = paths.SelectMany(x => extensions,
            (path, extension) => Path.Combine(path, filename + extension));
    return combinations.FirstOrDefault(File.Exists);
}

Sorry the indentation's a bit all-over-the-place - I was trying to make it not scroll. I don't know if the StartsWith check is really necessary - I'm not sure how CMD copes with pathext entries without a leading dot.

Upvotes: 15

Serj-Tm
Serj-Tm

Reputation: 16981

public static string GetFullPath(string filename)    
{
 return new[]{Environment.CurrentDirectory}
  .Concat(Environment.GetEnvironmentVariable("PATH").Split(';'))
  .Select(dir => Path.Combine(dir, filename))
  .FirstOrDefault(path => File.Exists(path));
}

Upvotes: 9

CodeCaster
CodeCaster

Reputation: 151588

If you're only interested in searching the current directory and the paths specified in the PATH environment variable, you can use this snippet:

public static string GetFullPath(string fileName)
{
    if (File.Exists(fileName))
        return Path.GetFullPath(fileName);

    var values = Environment.GetEnvironmentVariable("PATH");
    foreach (var path in values.Split(';'))
    {
        var fullPath = Path.Combine(path, fileName);
        if (File.Exists(fullPath))
            return fullPath;
    }

    return null;
}

Upvotes: 4

Simon Whitehead
Simon Whitehead

Reputation: 65049

You have to search the entire disk.

Windows can respond to things like, iexplore, ping, cmd, etc, because they are in the registry under this key:

HKEY_LOCAL_MACHINE
   SOFTWARE
       Microsoft
           Windows
               CurrentVersion
                   App Paths

The only other way is to search the entire disk for the application.

EDIT: My understanding was, that you want to search for any random executable name, not the ones that are already known to Windows..

Upvotes: 3

Tamir
Tamir

Reputation: 3901

internal class Program
{
    static void Main(string[] args)
    {
        string fullPath = GetExactPathFromEnvironmentVar("ping.exe");
        if (!string.IsNullOrWhiteSpace(fullPath))
            Console.WriteLine(fullPath);
        else
            Console.WriteLine("Not found");
    }

    static string GetExactPathFromEnvironmentVar(string program)
    {
        var pathVar = System.Environment.GetEnvironmentVariable("PATH");
        string[] folders = pathVar.Split(';');

        foreach (var folder in folders)
        {
            string path = Path.Combine(folder, program);
            if (File.Exists(path))
            {
                return path;
            }
        }

        return null;
    }
}

HTH

Upvotes: 2

Related Questions