Получить путь к исполняемому из команды (как это делает cmd)

Учитывая путь стиля командной строки к команде, такой как bin/server.exe или ping, как я могу получить полный путь к этому исполняемому файлу (так как cmd или Process.Start разрешат его)?

Я пробовал Path.GetFullPath, но он всегда расширяется относительно рабочего каталога. Он правильно расшифровывает bin/server.exe, но, учитывая ping, он возвращает c:\users\matt\ping (несуществующий). Я хочу c:\Windows\system32\ping.exe.

Изменить: Мне хотелось бы, чтобы это было так же, как cmd. Некоторые соображения:

  • Когда есть локальный исполняемый файл с тем же именем, что и один в пути, cmd предпочитает локальный
  • cmd может расширить команду server до server.bat или server.exe (добавление расширения файла)

Я также попробовал инструмент командной строки Windows под названием where. Мне это почти нравится:

Отображает расположение файлов, соответствующих шаблону поиска. По умолчанию поиск выполняется по текущему каталогу и по путям, указанным переменной среды PATH.

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

(Этот вопрос трудно найти вокруг из-за двух разных значений слова "путь" )

Ответ 1

С учетом PATHEXT тоже, крадя у Serj-Tm ответ (извините! +1 ему):

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);
}

Извините, что отступы немного повсюду - я пытался сделать это не прокруткой. Я не знаю, действительно ли проверка StartsWith необходима - я не уверен, как CMD справляется с элементами pathext без ведущей точки.

Ответ 2

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));
}

Ответ 3

Если вас интересует только текущий каталог и пути, указанные в переменной среды PATH, вы можете использовать этот фрагмент:

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;
}

Ответ 4

Вам нужно выполнить поиск по всему диску.

Windows может реагировать на такие вещи, как iexplore, ping, cmd и т.д., потому что они находятся в реестре под этим ключом:

HKEY_LOCAL_MACHINE
   SOFTWARE
       Microsoft
           Windows
               CurrentVersion
                   App Paths

Другим способом является поиск всего диска для приложения.

EDIT: Я понял, что вы хотите найти произвольное исполняемое имя, а не те, которые уже известны Windows.

Ответ 5

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;
    }
}

НТН