在Windows命令行上是否有一个等效的“哪个”?

由于我有时遇到路径问题,我自己的一个cmd脚本被另一个程序隐藏(阴影)(在路径的前面),我希望能够在Windows命令行上找到程序的完整路径,只给出它的名称。

是否有一个等同于UNIX命令“哪个”?

在UNIX上,which command打印给定命令的完整路径,以轻松查找和修复这些阴影问题。

786099 次浏览

不在Windows中,但它是由Unix的服务提供的,并且有几个简单的批处理脚本可以完成同样的事情,例如这个这一个

我在Windows上找到的最好的版本是Joseph Newcomer的“在哪里”实用程序,它可以从他的网站获得(带有源代码)。

关于“何地”发展的文章值得一读。

如果您安装了PowerShell(我推荐),您可以使用以下命令作为粗略的等效命令(将程序名称替换为可执行文件的名称):

($Env:Path).Split(";") | Get-ChildItem -filter programName*

更多在这里:我的Manwich!PowerShell哪个

虽然更高版本的Windows有where命令,但您也可以通过使用环境变量修饰符在Windows XP中执行此操作,如下所示:

c:\> for %i in (cmd.exe) do @echo.   %~$PATH:iC:\WINDOWS\system32\cmd.exe
c:\> for %i in (python.exe) do @echo.   %~$PATH:iC:\Python25\python.exe

您不需要任何额外的工具,它不限于PATH,因为您可以替换您希望使用的任何环境变量(当然是路径格式)。


而且,如果你想要一个可以处理PATHEXT中所有扩展的扩展(就像Windows本身一样),这个就可以了:

@echo offsetlocal enableextensions enabledelayedexpansion
:: Needs an argument.
if "x%1"=="x" (echo Usage: which ^<progName^>goto :end)
:: First try the unadorned filenmame.
set fullspec=call :find_it %1
:: Then try all adorned filenames in order.
set mypathext=!pathext!:loop1:: Stop if found or out of extensions.
if "x!mypathext!"=="x" goto :loop1end
:: Get the next extension and try it.
for /f "delims=;" %%j in ("!mypathext!") do set myext=%%jcall :find_it %1!myext!
:: Remove the extension (not overly efficient but it works).
:loop2if not "x!myext!"=="x" (set myext=!myext:~1!set mypathext=!mypathext:~1!goto :loop2)if not "x!mypathext!"=="x" set mypathext=!mypathext:~1!
goto :loop1:loop1end
:endendlocalgoto :eof
:: Function to find and print a file in the path.
:find_itfor %%i in (%1) do set fullspec=%%~$PATH:iif not "x!fullspec!"=="x" @echo.   !fullspec!goto :eof

它实际上返回所有可能性,但您可以针对特定的搜索规则轻松调整它。

Windows Server 2003及更高版本(即Windows XP 32位之后的任何内容)提供where.exe程序,该程序执行which的一些功能,尽管它匹配所有类型的文件,而不仅仅是可执行命令。(它不匹配像cd这样的内置shell命令。)它甚至可以接受通配符,所以where nt*可以找到%PATH%和当前目录中名称以nt开头的所有文件。

where /?寻求帮助。

请注意,Windows PowerShell将where定义为#1 cmdlet的别名,因此如果您想要where.exe,则需要键入全名而不是省略.exe扩展名。或者,您可以为其设置别名:

Set-Alias which where.exe

更新时间:建议使用Get-Command(别名:gcm),因为它是PS的原生命令,并将获取所有命令类型:别名、cmdlet、可执行文件和函数。示例:

gcm notepad*

GnuWin32工具有which,还有一大堆其他Unix工具。

我创建了类似于Ned Batchold的工具:

在PATH中搜索. dll和. exe文件

虽然我的工具主要用于搜索各种dll版本,但它显示更多信息(日期、大小、版本),但它不使用PATHEXT(我希望很快更新我的工具)。

从这里获取unxutils:http://sourceforge.net/projects/unxutils/

Windows平台上的黄金,将所有漂亮的unix实用程序放在标准的windows DOS上。已经使用多年了。

它包含一个“哪个”。请注意,它是区分大小写的。

注意:要安装它,请在某处爆炸zip并将…\UnxUtils\usr\Local\wbin\添加到您的系统路径env变量中。

如果你能找到一个免费的Pascal编译器,你可以编译它。至少它可以工作并显示必要的算法。

program Whence (input, output);Uses Dos, my_funk;Const program_version = '1.00';program_date    = '17 March 1994';VAR   path_str          : string;command_name      : NameStr;command_extension : ExtStr;command_directory : DirStr;search_dir        : DirStr;result            : DirStr;

procedure Check_for (file_name : string);{ Check existence of the passed parameter. If exists, then state so   }{ and exit.                                                           }beginif Fsearch(file_name, '') <> '' thenbeginWriteLn('DOS command = ', Fexpand(file_name));Halt(0);    { structured ? whaddayamean structured ? }end;end;
function Get_next_dir : DirStr;{ Returns the next directory from the path variable, truncating the   }{ variable every time. Implicit input (but not passed as parameter)   }{ is, therefore, path_str                                             }var  semic_pos : Byte;
beginsemic_pos := Pos(';', path_str);if (semic_pos = 0) thenbeginGet_next_dir := '';Exit;end;
result := Copy(Path_str, 1, (semic_pos - 1));  { return result   }{ Hmm! although *I* never reference a Root drive (my directory tree) }{ is 1/2 way structured), some network logon software which I run    }{ does (it adds Z:\ to the path). This means that I have to allow    }{ path entries with & without a terminating backslash. I'll delete   }{ anysuch here since I always add one in the main program below.     }if (Copy(result, (Length(result)), 1) = '\') thenDelete(result, Length(result), 1);
path_str := Copy(path_str,(semic_pos + 1),(length(path_str) - semic_pos));Get_next_dir := result;end;  { Of function get_next_dir }
begin{ The following is a kludge which makes the function Get_next_dir easier  }{ to implement. By appending a semi-colon to the end of the path         }{ Get_next_dir doesn't need to handle the special case of the last entry }{ which normally doesn't have a semic afterwards. It may be a kludge,    }{ but it's a documented kludge (you might even call it a refinement).    }path_str := GetEnv('Path') + ';';
if (paramCount = 0) thenbeginWriteLn('Whence: V', program_version, ' from ', program_date);Writeln;WriteLn('Usage: WHENCE command[.extension]');WriteLn;WriteLn('Whence is a ''find file''type utility witha difference');Writeln('There are are already more than enough of those :-)');Write  ('Use Whence when you''re not sure where a command which you ');WriteLn('want to invoke');WriteLn('actually resides.');Write  ('If you intend to invoke the command with an extension e.g ');Writeln('"my_cmd.exe param"');Write  ('then invoke Whence with the same extension e.g ');WriteLn('"Whence my_cmd.exe"');Write  ('otherwise a simple "Whence my_cmd" will suffice; Whence will ');Write  ('then search the current directory and each directory in the ');Write  ('for My_cmd.com, then My_cmd.exe and lastly for my_cmd.bat, ');Write  ('just as DOS does');Halt(0);end;
Fsplit(paramStr(1), command_directory, command_name, command_extension);if (command_directory <> '') thenbeginWriteLn('directory detected *', command_directory, '*');Halt(0);end;
if (command_extension <> '') thenbeginpath_str := Fsearch(paramstr(1), '');    { Current directory }if   (path_str <> '') then WriteLn('Dos command = "', Fexpand(path_str), '"')elsebeginpath_str := Fsearch(paramstr(1), GetEnv('path'));if (path_str <> '') then WriteLn('Dos command = "', Fexpand(path_str), '"')else Writeln('command not found in path.');end;endelsebegin{ O.K, the way it works, DOS looks for a command firstly in the current  }{ directory, then in each directory in the Path. If no extension is      }{ given and several commands of the same name exist, then .COM has       }{ priority over .EXE, has priority over .BAT                             }
Check_for(paramstr(1) + '.com');     { won't return if file is found }Check_for(paramstr(1) + '.exe');Check_for(paramstr(1) + '.bat');
{ Not in current directory, search through path ... }
search_dir := Get_next_dir;
while (search_dir <> '') dobeginCheck_for(search_dir + '\' + paramstr(1) + '.com');Check_for(search_dir + '\' + paramstr(1) + '.exe');Check_for(search_dir + '\' + paramstr(1) + '.bat');search_dir := Get_next_dir;end;
WriteLn('DOS command not found: ', paramstr(1));end;end.

Cygwin是一个解决方案。如果您不介意使用第三方解决方案,那么Cygwin就是您的选择。

Cygwin在Windows环境中为您提供了*nix的舒适性(您可以在Windows命令shell中使用它,或者使用您选择的*nix shell)。它为您提供了大量适用于Windows的*nix命令(如which),您可以将该目录包含在您的PATH中。

在Windows PowerShell中:

set-alias which where.exe

在PowerShell下,#0可以在$Env:PATH中的任何位置找到可执行文件。

$ Get-Command eventvwr
CommandType   Name          Definition-----------   ----          ----------Application   eventvwr.exe  c:\windows\system32\eventvwr.exeApplication   eventvwr.msc  c:\windows\system32\eventvwr.msc

由于PowerShell允许您定义别名,因此可以像这样定义which

$ sal which gcm   # short form of `Set-Alias which Get-Command`$ which foo...

PowerShell命令不仅仅是可执行文件(.exe.ps1等)。它们还可以是cmdlet、函数、别名、$Env:PATHEXT中设置的自定义可执行后缀等。#3能够查找并列出所有这些命令(非常类似于Bash的type -a foo)。仅此一点就比where.exewhich.exe等更好,这些命令通常仅限于查找可执行文件。

仅使用部分名称查找可执行文件

$ gcm *disk*
CommandType     Name                             Version    Source-----------     ----                             -------    ------Alias           Disable-PhysicalDiskIndication   2.0.0.0    StorageAlias           Enable-PhysicalDiskIndication    2.0.0.0    StorageFunction        Add-PhysicalDisk                 2.0.0.0    StorageFunction        Add-VirtualDiskToMaskingSet      2.0.0.0    StorageFunction        Clear-Disk                       2.0.0.0    StorageCmdlet          Get-PmemDisk                     1.0.0.0    PersistentMemoryCmdlet          New-PmemDisk                     1.0.0.0    PersistentMemoryCmdlet          Remove-PmemDisk                  1.0.0.0    PersistentMemoryApplication     diskmgmt.msc                     0.0.0.0    C:\WINDOWS\system32\diskmgmt.mscApplication     diskpart.exe                     10.0.17... C:\WINDOWS\system32\diskpart.exeApplication     diskperf.exe                     10.0.17... C:\WINDOWS\system32\diskperf.exeApplication     diskraid.exe                     10.0.17... C:\WINDOWS\system32\diskraid.exe...

查找自定义可执行文件

与UNIX不同,其中可执行文件是设置了可执行文件(+x)位的文件,Windows上的可执行文件是存在于$PATH env.变量中指定的目录之一中的文件,其文件名后缀在$PATHEXT env.变量中命名(默认为.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL)。

由于#0也尊重这个环境。变量,它可以扩展为列出自定义可执行文件。例如

$ $Env:PATHEXT="$Env:PATHEXT;.dll;.ps1;.psm1;.py"     # temporary assignment, only for this shell's process
$ gcm user32,kernel32,*WASM*,*http*py
CommandType     Name                        Version    Source-----------     ----                        -------    ------ExternalScript  Invoke-WASMProfiler.ps1                C:\WINDOWS\System32\WindowsPowerShell\v1.0\Invoke-WASMProfiler.ps1Application     http-server.py              0.0.0.0    C:\Users\ME\AppData\Local\Microsoft\WindowsApps\http-server.pyApplication     kernel32.dll                10.0.17... C:\WINDOWS\system32\kernel32.dllApplication     user32.dll                  10.0.17... C:\WINDOWS\system32\user32.dll

更多选项和示例见#0

我在Internet上找到的Unix的Win32端口都不是令人满意的,因为它们都有以下一个或多个缺点:

  • 不支持Windows PATHEXT变量。(它定义了在扫描路径之前隐含添加到每个命令的扩展列表,以及顺序。)(我使用了很多tcl脚本,没有公开可用的工具可以找到它们。)
  • 不支持cmd.exe代码页,这使得它们错误地显示非ascii字符的路径。(我对此非常敏感,我的名字中的ç:-))
  • 不支持cmd.exe和PowerShell命令行中的不同搜索规则。(没有公开可用的工具会在PowerShell窗口中找到. ps1脚本,但不会在cmd窗口中找到!)

所以我最终写了我自己的,支持上述所有正确。

这里有:http://jf.larvoire.free.fr/progs/which.exe

我的PowerShell配置文件中有一个名为“which”的函数

function which {get-command $args[0]| format-list}

这是输出的样子:

PS C:\Users\fez> which python

Name            : python.exeCommandType     : ApplicationDefinition      : C:\Python27\python.exeExtension       : .exePath            : C:\Python27\python.exeFileVersionInfo : File:             C:\Python27\python.exeInternalName:OriginalFilename:FileVersion:FileDescription:Product:ProductVersion:Debug:            FalsePatched:          FalsePreRelease:       FalsePrivateBuild:     FalseSpecialBuild:     FalseLanguage:

对于Windows XP用户(没有内置where命令),我编写了一个名为whichr的rubygem的“where like”命令。

要安装它,请安装Ruby。

然后

gem install whichr

运行它像:

C:cmd_here

在PowerShell中,它是gcm,它提供有关其他命令的格式化信息。如果您只想检索可执行文件的路径,请使用.Source

例如:gcm git(gcm git).Source

花絮:

在Windows CMDwhich调用where

$ where phpC:\Program Files\PHP\php.exe

此批处理文件使用CMD变量处理来查找将在路径中执行的命令。注意:当前目录始终在路径之前完成),并且根据使用的API调用,在路径之前/之后搜索其他位置。

@echo offecho.echo PathFind - Finds the first file in in a pathecho ======== = ===== === ===== ==== == == = ====echo.echo Searching for %1 in %path%echo.set a=%~$PATH:1If "%a%"=="" (Echo %1 not found) else (echo %1 found at %a%)

set /?寻求帮助。

来自JPSoft的TCC和TCC/LE是CMD.EXE的替代品,增加了重要的功能。

您可以先从下载Git安装Git,然后打开Git Bash并输入:

which app-name

我正在使用GOW(Windows上的GNU),它是Cygwin的轻量级版本。您可以从GitHub这里获取它。

GOW(Windows上的GNU)是Cygwin的轻量级替代品。它使用一个方便的Windows安装程序,安装约130非常编译为原生win32的有用的开源UNIX应用程序二进制文件。它被设计为尽可能小,大约10 MB,因为与Cygwin相反,Cygwin可以运行超过100 MB,具体取决于选项。-关于描述(Brent R. Matzelle)

GOW中包含的命令列表的屏幕截图:

在此输入图片描述

我使用npm中的which模块已经有一段时间了,它运行得很好:https://www.npmjs.com/package/which这是一个很好的多平台选择。

现在我切换到Git附带的which。只需将来自Git的/usr/bin路径添加到您的路径中,通常位于C:\Program Files\Git\usr\bin\which.exewhich二进制文件将位于C:\Program Files\Git\usr\bin\which.exe。它更快,也按预期工作。

试试这个

set a=%~$dir:1If "%for%"=="" (Echo %1 not found) else (echo %1 found at %a%)

只需发布这个Windows的一个班轮批处理文件:

C:>type wh.cmd@for %%f in (%*) do for %%e in (%PATHEXT% .dll .lnk) do for %%b in (%%f%%e) do for %%d in (%PATH%) do if exist %%d\%%b echo %%d\%%b

一个测试:

C:>wh sshC:\cygwin64\bin\ssh.EXEC:\Windows\System32\OpenSSH\\ssh.EXE

如果您将代码包装在setlocal enableextensionsendlocal中,则不完全是一行代码。

可以从这个GitHub存储库下载为Windows编译的所有UNIX命令,包括whichhttps://github.com/George-Ogden/UNIX

这是我为查找类似于Unix命令“WHCH”的可执行文件所做的函数

app_path_func.cmd:

@ECHO OFFCLS
FOR /F "skip=2 tokens=1,2* USEBACKQ" %%N IN (`reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\%~1" /t REG_SZ  /v "Path"`) DO (IF /I "%%N" == "Path" (SET wherepath=%%P%~1GoTo Found))
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe %~1`) DO (SET wherepath=%%FGoTo Found)
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe /R "%PROGRAMFILES%" %~1`) DO (SET wherepath=%%FGoTo Found)
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe /R "%PROGRAMFILES(x86)%" %~1`) DO (SET wherepath=%%FGoTo Found)
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe /R "%WINDIR%" %~1`) DO (SET wherepath=%%FGoTo Found)
:FoundSET %2=%wherepath%:End

测试:

@ECHO OFFCLS
CALL "app_path_func.cmd" WINWORD.EXE PROGPATHECHO %PROGPATH%
PAUSE

结果:

C:\Program Files (x86)\Microsoft Office\Office15\Press any key to continue . . .

https://www.freesoftwareservers.com/display/FREES/Find+Executable+via+Batch+-+Microsoft+Office+Example+-+WINWORD+-+Find+Microsoft+Office+Path