Windows命令行中是否有类似于“which”的等效命令?

2806

有时候我会遇到路径问题,因为我的一个cmd脚本被其他程序(在路径上更早的位置)隐藏了,所以我想通过给出程序名来查找Windows命令行中程序的完整路径。

是否有类似于UNIX命令“which”的命令?

在UNIX中,“which command”命令可以打印给定命令的完整路径,以便轻松查找和修复这些隐藏问题。


3
Foredecker:“which”会在PATH中搜索可执行文件,以便在Shell提示符下键入命令时运行该文件。 - Greg Hewgill
3
举例来说,如果你安装了5个版本的Java并且不知道正在使用哪一个,你可以输入“which java”,它会给你显示二进制文件的路径。请注意,我会尽力在保持原意的基础上使翻译内容更易懂,但不会添加解释或其他额外的内容。 - ninesided
11
@Foredecker,MR 说在 Win2k3 中应该用 "where",但问题并没有涉及到 Win2k3。如果其他 Windows 版本中没有 "where",那么其他回答也是有效的。在我看来,在所有的 Windows 版本上都能工作的答案是最好的。此外,其他答案也不是错的,只是不同的方法而已。 - paxdiablo
43
我知道这个问题在SuperUser之前就出现了,但它可能更适合在那里询问。 - palswim
26
标准Unix中没有which命令。POSIX实用程序是type。C Shell有一个which命令,一些系统将其作为外部可执行文件。例如,在Debian Linux上,which来自一个名为debutils的软件包。这个外部的which不能"看到"shell内置、别名或函数。type可以;Bash的type有一个选项可以抑制这种行为,只进行路径查找。 - Kaz
显示剩余4条评论
27个回答

2975

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

请输入where /?获取帮助。

请注意,Windows PowerShell将where定义为Where-Object cmdlet的别名,因此如果您想要使用where.exe,则需要输入完整名称,而不是省略.exe扩展名。或者,您可以为它设置别名:

Set-Alias which where.exe

更新:推荐使用Get-Command(别名: gcm),因为它是 PowerShell 原生命令,可以获取所有类型的命令:别名、Cmdlet、可执行文件和函数。示例:

gcm notepad*

32
不行,因为 grep 检查其输入的内容,需要显式地提供。而 whichwhere.exe 只查看在 PATH 环境变量设置的一组目录中文件的名称。 - Michael Ratanapintha
21
请记住,where.exe 不是一个内置的命令,您需要在 %PATH% 环境变量中添加 %windir%\system32 才能正常使用它。但这可能不是默认设置,如果您需要使用 where 命令,则说明您可能正在解决与环境变量路径相关的问题! - Tomasz Gandor
2
在 Server 2016 上在 CMD 中没有输入 where.exe 就无法工作。 - Edward
4
也适用于 Windows 10。 - Emil Stenström
9
需要明确的是:where.exe 可能返回多个值,此时将调用第一个/最顶部的值。示例: C:\Windows\System32> where.exe sqlcmd.exe c:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\110\Tools\Binn\SQLCMD.EXE - phantom-99w
显示剩余5条评论

317

尽管Windows的较新版本带有where命令,但你也可以通过使用环境变量修饰符在Windows XP上实现此功能,方法如下:

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

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

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


如果您想使用一个可以处理PATHEXT中的所有扩展名(就像Windows本身所做的那样),这个可以胜任:

@echo off
setlocal 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=%%j
    call :find_it %1!myext!

:: Remove the extension (not overly efficient but it works).

:loop2
    if 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

:end
endlocal
goto :eof

:: Function to find and print a file in the path.

:find_it
    for %%i in (%1) do set fullspec=%%~$PATH:i
    if not "x!fullspec!"=="x" @echo.   !fullspec!
    goto :eof

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


8
嘿,我希望我早些学会这个!可惜这在MS-DOS或Win9x(也就是command.com)上不起作用。Raymond Chen有一个更“详细”的版本,你可以将其转换为批处理文件:http://blogs.msdn.com/oldnewthing/archive/2005/01/20/357225.aspx - Michael Ratanapintha
135
@Michael,如果你仍在使用DOS或Win95,那么在路径上找到可执行文件只是你问题中的最小部分 :-) - paxdiablo
Windows 可以识别更多的可执行文件格式,而不仅仅是 .exe。我上次编写 which 命令还是在 W95/DOS 时代,当时搜索顺序是:当前目录,然后是每个路径目录,对于 cmd.com,先执行当前目录下的 cmd.bat,再执行路径中的 cmd.exe。因此,即使当前目录下有 cmd.bat,也会先执行它,而不是路径中的 cmd.exe。 - Mawg says reinstate Monica
3
@mawg,原始问题是关于在UNIX系统下知道文件扩展名的情况(这里没有扩展名添加技巧)。我已经添加了一个可以实现您要求的方法,但它不再是一个简单的命令,而是一个脚本。它首先尝试未加修饰的命令,然后尝试每个扩展名的命令。希望这可以帮到您。您可以根据需要进行调整(例如,如果您想要与Windows相同的搜索顺序-此脚本会显示所有可能性)。 - paxdiablo
2
将此转换为批处理脚本,请创建一个名为“which.bat”的文件:@echo off for %%i in (%1) do @echo. %%~$PATH:%i要将其添加到每次运行cmd.exe时加载的alias.bat脚本中(将上述脚本放入名为C:\ usr \ aliases的新目录中):DOSKEY which=C:\usr\aliases\which.bat $*然后,您可以创建一个脚本来使用alias.bat文件启动cmd.exe:cmd.exe /K E:\usr\aliases\alias.bat - Brad T.
显示剩余2条评论

246

在 PowerShell 下,Get-Command 可以在 $Env:PATH 的任何位置查找可执行文件。

$ Get-Command eventvwr

CommandType   Name          Definition
-----------   ----          ----------
Application   eventvwr.exe  c:\windows\system32\eventvwr.exe
Application   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等),它们也可以是cmdlets、函数、别名、在$Env:PATHEXT中设置的自定义可执行后缀等。 Get-Command 可以查找并列出所有这些命令(类似于Bash的type -a foo)。仅此一点就使它比where.exewhich.exe等更好,这些通常只能找到可执行文件。

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

$ gcm *disk*

CommandType     Name                             Version    Source
-----------     ----                             -------    ------
Alias           Disable-PhysicalDiskIndication   2.0.0.0    Storage
Alias           Enable-PhysicalDiskIndication    2.0.0.0    Storage
Function        Add-PhysicalDisk                 2.0.0.0    Storage
Function        Add-VirtualDiskToMaskingSet      2.0.0.0    Storage
Function        Clear-Disk                       2.0.0.0    Storage
Cmdlet          Get-PmemDisk                     1.0.0.0    PersistentMemory
Cmdlet          New-PmemDisk                     1.0.0.0    PersistentMemory
Cmdlet          Remove-PmemDisk                  1.0.0.0    PersistentMemory
Application     diskmgmt.msc                     0.0.0.0    C:\WINDOWS\system32\diskmgmt.msc
Application     diskpart.exe                     10.0.17... C:\WINDOWS\system32\diskpart.exe
Application     diskperf.exe                     10.0.17... C:\WINDOWS\system32\diskperf.exe
Application     diskraid.exe                     10.0.17... C:\WINDOWS\system32\diskraid.exe
...

查找自定义可执行文件

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

由于Get-Command也遵守此环境变量,因此可以将其扩展以列出自定义可执行文件。例如:

$ $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.ps1
Application     http-server.py              0.0.0.0    C:\Users\ME\AppData\Local\Microsoft\WindowsApps\http-server.py
Application     kernel32.dll                10.0.17... C:\WINDOWS\system32\kernel32.dll
Application     user32.dll                  10.0.17... C:\WINDOWS\system32\user32.dll

更多选项和示例,请参见Get-Command


3
它不仅可以找到可执行文件,还可以捕获命令文件。 - Maximilian Burszley
2
@TheIncorrigible1 - 如果你指的是批处理文件(.BAT.CMD等),它们被认为是可执行文件,因为它们的扩展名在PATHEXT变量中命名(默认情况下为PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL)。其他可执行文件类型(例如.py.rb等)可以通过添加文件扩展名并使用assoc/ftype创建可执行关联来添加 - 例如:https://docs.python.org/3.3/using/windows.html#executing-scripts-without-the-python-launcher - shalomb
3
考虑到原始答案是在2008年发布的,所以现在应该将此答案作为最佳答案。时代已经变了。PowerShell是一种新的方式,特别是因为现在这个答案是跨平台的,适用于任何存在PowerShell的地方。 - ScriptAutomate

70
在Windows PowerShell中:
set-alias which where.exe

45
如果您已经安装了PowerShell(我建议这样做),您可以使用以下命令作为粗略等效的方式(将programName替换为可执行文件的名称):

如果您已经安装了PowerShell(我建议这样做),您可以使用以下命令作为粗略等效的方式(将programName替换为可执行文件的名称):

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

更多内容请查看:我的Manwich!PowerShell Which


1
我一直在寻找这个简洁的PowerShell命令。我之前一直在使用where.exe,但是需要处理错误代码以及解析其输出,这远不如本地PowerShell解决方案。谢谢! - scobi
10
但是"$Env:Path".Split(";") | Get-ChildItem -filter programName* 很容易打出来... ;-) - Craig Tullis
如果您的路径中有一个通常由系统解析的变量(例如%JAVA_HOME%),那么这也会失败。 - dragon788
我无法让which.exe工作,我尝试了这个方法,它起作用了。 - Asfand Qazi
1
“gcm” 的答案在今天的 PowerShell 中会更好用:https://dev59.com/6HVC5IYBdhLWcg3wZwTj#27140194 - ScriptAutomate

39

GnuWin32工具集中包含了which命令以及其他许多Unix工具。


32
在 Windows CMD 中,which 命令会调用 where 命令。
$ where php
C:\Program Files\PHP\php.exe

1
哪里会列出所有可用的资源。我使用了 where pip,并得到了三个结果。我不确定哪一个是被执行的。 - Tek Kshetri
2
你的回答与被接受的答案本质上并没有太大区别,也没有提供任何新的价值或信息。请避免编写重复的答案,要么编辑您的答案以增加价值,要么完全删除它,这将确保网站上的所有问题和答案都是有用的而不是分散/重复的。 - Stephan Vierkant
1
@Tekson,列表中的第一个将被执行。 - inavda

18

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

Cygwin在Windows环境中提供了类Unix的舒适体验(您可以在Windows命令行中使用它,或者使用您选择的类Unix shell)。它提供了许多类Unix命令(如which)供Windows使用,并且您只需将该目录包含在PATH中即可。


10
在这种情况下,Ferruccio之前提到的GnuWin32更好,因为它可以让你单独使用本地的where可执行文件。 - Piotr Dobrogost
GnuWin32非常好用,我也在使用它,但如果你想要这个功能而不安装GnuWin32工具,where.exe似乎是正确的选择。虽然如此,我会将GnuWin32工具放在我们网络上的\bin$共享文件夹中,这样我就可以在没有本地安装它们的工作站(以及批处理文件)上使用它们了。 - Craig Tullis
1
当我们谈论在Windows中使用Cygwin时,我更喜欢使用: cygpath -w "`which <appname>`" - mpasko256

14
在PowerShell中,使用gcm可以获取其他命令的格式化信息。如果您只想检索可执行文件的路径,请使用.Source
例如:gcm git(gcm git).Source 小贴士:

12

我在PowerShell文件中有一个名为'which'的函数。

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

这是输出的样子:

PS C:\Users\fez> which python


Name            : python.exe
CommandType     : Application
Definition      : C:\Python27\python.exe
Extension       : .exe
Path            : C:\Python27\python.exe
FileVersionInfo : File:             C:\Python27\python.exe
                  InternalName:
                  OriginalFilename:
                  FileVersion:
                  FileDescription:
                  Product:
                  ProductVersion:
                  Debug:            False
                  Patched:          False
                  PreRelease:       False
                  PrivateBuild:     False
                  SpecialBuild:     False
                  Language:

其他的解决方案都不适用于我,但是 > get-command app.exe | format-list 完美地解决了问题! - Alexander McFarlane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接