由于我有时会遇到路径问题,其中我自己的一个 cmd 脚本被另一个程序(路径上的早期)隐藏(隐藏),我希望能够在 Windows 命令行上找到程序的完整路径,给定只是它的名字。
是否有等效于 UNIX 命令“哪个”?
在 UNIX 上,which command
打印给定命令的完整路径,以便轻松查找和修复这些阴影问题。
which
命令。 POSIX 实用程序是 type
。 C Shell 有一个 which 命令,有些系统将它作为外部可执行文件。例如,在 Debian Linux 上,which
来自一个名为 debutils
的软件包。此外部 which
不会“看到”shell 内置函数、别名或函数。 type
有; Bash 的 type
有一个选项来抑制它并只进行路径查找。
Windows Server 2003 及更高版本(即 Windows XP 32 位之后的任何版本)提供了 where.exe
程序,它执行 which
的某些功能,但它匹配所有类型的文件,而不仅仅是可执行命令。 (它不匹配像 cd
这样的内置 shell 命令。)它甚至可以接受通配符,因此 where nt*
会在您的 %PATH%
和当前目录中查找名称以 nt
开头的所有文件。
请尝试 where /?
寻求帮助。
请注意,Windows PowerShell 将 where
定义为 the Where-Object
cmdlet 的别名,因此如果需要 where.exe
,则需要键入全名而不是省略 .exe
扩展名。或者,您可以为其设置别名:
Set-Alias which where.exe
更新: 建议使用 Get-Command
(别名:gcm
),因为它是 PS 原生的,可以获取所有命令类型:别名、cmdlet、可执行文件和函数。例子:
gcm notepad*
虽然更高版本的 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
它实际上返回所有可能性,但您可以很容易地调整它以适应特定的搜索规则。
which
时,搜索顺序是 - 当前目录,然后是每个路径目录,对于 cmd.com,然后是 cmd.exe,然后是 cmd.bat 所以,甚至 cmd.bat 在当前目录在路径中的 cmd.exe soemwhere 之前执行
@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
在 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
等)。它们也可以是 cmdlet、函数、别名、在 $Env:PATHEXT
中设置的自定义可执行后缀等。Get-Command
能够找到并列出所有这些命令(非常类似于 Bash 的 type -a foo
)。仅此一项就使其优于 where.exe
、which.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 不同,其中可执行文件是设置了可执行 (+x
) 位的文件,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
。
.BAT
、.CMD
等),它们被视为可执行文件,因为它们的扩展名在 PATHEXT
变量中命名(默认情况下是 PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL
)。可以通过添加文件扩展名并与 assoc
/ftype
创建可执行关联来添加其他可执行类型(例如 .py
、.rb
等) - 例如 docs.python.org/3.3/using/…
在 Windows PowerShell 中:
set-alias which where.exe
如果您安装了 PowerShell(我推荐),则可以使用以下命令作为大致等效命令(将 programName 替换为可执行文件的名称):
($Env:Path).Split(";") | Get-ChildItem -filter programName*
更多内容在这里:My Manwich! PowerShell Which
($Env:Path).Split(";") | Get-ChildItem -filter programName*
很容易输入... ;-)
gcm
的答案是今天更好地使用 PowerShell:stackoverflow.com/a/27140194/5340149
在 Windows CMD which
调用 where
中:
$ where php
C:\Program Files\PHP\php.exe
where pip
,得到了三个结果。我不确定哪一个是被执行的。
Cygwin 是一个解决方案。如果您不介意使用第三方解决方案,那么 Cygwin 就是您的最佳选择。
Cygwin 为您提供了在 Windows 环境中使用 *nix 的舒适性(您可以在 Windows 命令 shell 中使用它,或者使用您选择的 *nix shell)。它为您提供了一整套适用于 Windows 的 *nix 命令(如 which
),您只需将该目录包含在 PATH
中即可。
在 PowerShell 中,它是 gcm
,它提供有关其他命令的格式化信息。如果您只想检索可执行文件的路径,请使用 .Source
。
例如:gcm git
或 (gcm git).Source
花絮:
适用于 Windows XP。
从 PowerShell 1.0 开始可用。
gcm 是 Get-Command cmdlet 的别名。
没有任何参数,它会列出主机 shell 提供的所有可用命令。
您可以使用 Set-Alias which gcm 创建一个自定义别名,并像这样使用它:(which git).Source。
官方文档:https://technet.microsoft.com/en-us/library/ee176842.aspx
我的 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
效果很好!
从这里获取 unxutils:http://sourceforge.net/projects/unxutils/
windows平台上的gold,将所有漂亮的unix实用程序放在标准的windows DOS上。多年来一直在使用它。
它包含一个“哪个”。请注意,它是区分大小写的。
注意:要安装它,请在某处爆炸 zip 并将 ...\UnxUtils\usr\local\wbin\ 添加到您的系统路径环境变量中。
.
,grep 将不会匹配 EOL。这是一个 99% 的解决方案,但可以肯定!
如果你能找到一个免费的 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. }
begin
if Fsearch(file_name, '') <> '' then
begin
WriteLn('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;
begin
semic_pos := Pos(';', path_str);
if (semic_pos = 0) then
begin
Get_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) = '\') then
Delete(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) then
begin
WriteLn('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 <> '') then
begin
WriteLn('directory detected *', command_directory, '*');
Halt(0);
end;
if (command_extension <> '') then
begin
path_str := Fsearch(paramstr(1), ''); { Current directory }
if (path_str <> '') then WriteLn('Dos command = "', Fexpand(path_str), '"')
else
begin
path_str := Fsearch(paramstr(1), GetEnv('path'));
if (path_str <> '') then WriteLn('Dos command = "', Fexpand(path_str), '"')
else Writeln('command not found in path.');
end;
end
else
begin
{ 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 <> '') do
begin
Check_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.
my_funk;
是不必要的。感谢您发布 Pascal 程序,让我想起了我的青春!可惜帕斯卡没有进化。
Windows 没有库存,但它由 Services for Unix 提供,并且有几个简单的批处理脚本可以完成同样的事情,例如 this one。
我在 Windows 上找到的最佳版本是 Joseph Newcomer 的“whereis”实用程序,可从 his site 获得(带有源代码)。
关于“whereis”发展的文章值得一读。
我在 Internet 上找到的 Unix 的 Win32 端口没有一个是令人满意的,因为它们都有以下一个或多个缺点:
不支持 Windows PATHEXT 变量。 (它定义了在扫描路径之前隐式添加到每个命令的扩展列表,以及按什么顺序。)(我使用了很多 tcl 脚本,并且没有公开可用的工具可以找到它们。)
不支持 cmd.exe 代码页,这使它们无法正确显示非 ascii 字符的路径。 (我对此非常敏感,我的名字中有ç :-))
不支持 cmd.exe 和 PowerShell 命令行中的不同搜索规则。 (没有公开可用的工具会在 PowerShell 窗口中找到 .ps1 脚本,但在 cmd 窗口中却找不到!)
所以我最终写了我自己的,它正确地支持了上述所有内容。
可用:http://jf.larvoire.free.fr/progs/which.exe
此批处理文件使用 CMD 变量处理来查找将在路径中执行的命令。注意:当前目录总是在路径之前完成)并且根据使用的 API 调用,在路径之前/之后搜索其他位置。
@echo off
echo.
echo PathFind - Finds the first file in in a path
echo ======== = ===== === ===== ==== == == = ====
echo.
echo Searching for %1 in %path%
echo.
set a=%~$PATH:1
If "%a%"=="" (Echo %1 not found) else (echo %1 found at %a%)
请参阅 set /?
获取帮助。
我正在使用 GOW(Windows 上的 GNU),它是 Cygwin 的轻量级版本。您可以从 GitHub here 获取它。
GOW(Windows 上的 GNU)是 Cygwin 的轻量级替代品。它使用一个方便的 Windows 安装程序来安装大约 130 个非常有用的开源 UNIX 应用程序,这些应用程序编译为本地 win32 二进制文件。它被设计为尽可能小,大约 10 MB,而 Cygwin 可以运行超过 100 MB,具体取决于选项。 - 关于描述(Brent R. Matzelle)
GOW 中包含的命令列表的屏幕截图:
https://i.stack.imgur.com/MUeFR.png
我创建了类似于 Ned Batchelder 的工具:
Searching .dll and .exe files in PATH
虽然我的工具主要用于搜索各种 dll 版本,但它会显示更多信息(日期、大小、版本),但它不使用 PATHEXT(我希望尽快更新我的工具)。
只需发布此 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 ssh
C:\cygwin64\bin\ssh.EXE
C:\Windows\System32\OpenSSH\\ssh.EXE
如果您将代码包装在 setlocal enableextensions
和 endlocal
中,那么就不是很单行了。
对于 Windows XP 用户(没有内置 where
命令),我编写了一个名为 whichr
的“where like”命令作为 rubygem。
要安装它,请安装 Ruby。
然后
gem install whichr
像这样运行它:
C:> whichr cmd_here
JPSoft 的 TCC 和 TCC/LE 是 CMD.EXE 替代品,增加了重要功能。与 OP 的问题相关,which
是 TCC 系列命令处理器的内置命令。
我已经使用 npm 的 which
模块有一段时间了,它运行良好:https://www.npmjs.com/package/which 它是一个很棒的多平台替代品。
现在我切换到 Git 附带的 which
。只需将来自 Git 的 /usr/bin
路径添加到您的路径,该路径通常位于 C:\Program Files\Git\usr\bin\which.exe
。 which
二进制文件将位于 C:\Program Files\Git\usr\bin\which.exe
。它速度更快,也可以按预期工作。
尝试这个
set a=%~$dir:1
If "%for%"=="" (Echo %1 not found) else (echo %1 found at %a%)
可以从以下 GitHub 存储库下载为 Windows 编译的所有 UNIX 命令,包括 which
:https://github.com/George-Ogden/UNIX
which
并不是其中之一,任何合理明确的“所有”定义。
这是我用来查找可执行文件的函数,类似于 Unix 命令“WHICH”
app_path_func.cmd:
@ECHO OFF
CLS
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%~1
GoTo Found
)
)
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe %~1`) DO (
SET wherepath=%%F
GoTo Found
)
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe /R "%PROGRAMFILES%" %~1`) DO (
SET wherepath=%%F
GoTo Found
)
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe /R "%PROGRAMFILES(x86)%" %~1`) DO (
SET wherepath=%%F
GoTo Found
)
FOR /F "tokens=* USEBACKQ" %%F IN (`where.exe /R "%WINDIR%" %~1`) DO (
SET wherepath=%%F
GoTo Found
)
:Found
SET %2=%wherepath%
:End
测试:
@ECHO OFF
CLS
CALL "app_path_func.cmd" WINWORD.EXE PROGPATH
ECHO %PROGPATH%
PAUSE
结果:
C:\Program Files (x86)\Microsoft Office\Office15\
Press any key to continue . . .
where.exe
不是内置的 shell,您需要在您的%PATH%
上安装%windir%\system32
- 情况可能并非如此,因为使用where
表明您可能正在处理您的路径问题!Get-Command
或gcm
等效于where