首页 > 解决方案 > PowerShell 命令的程序路径在哪里?

问题描述

命令“git”可从 PowerShell 获得,我想知道 git 在我的 PC 上安装在哪里,所以我尝试执行这样的“脚本”

PS> where git

但执行后我什么也看不到,只提示输入新命令。问题:如何在 Windows 10 中找到命令的路径?

标签: windowsgitpowershell

解决方案


现有的答案很有帮助,但我认为更系统的讨论也有帮助。

tl;博士

where是 PowerShell的cmdlet的内置别名Where-Object;要调用外部where.exe 程序,请.exe显式使用:[1]

# Note the use of '.exe' to disambiguate the external 'where.exe' program
# from PowerShell's built-in 'where' alias (for 'Where-Object').
PS> where.exe git
C:\Program Files\Git\cmd\git.exe

where.exe,其目的是返回系统路径中的可执行文件的完整路径(在$env:PATH环境变量中列出的目录之一中),(遗留命令处理器)无关cmd:它是Windows 附带的外部可执行文件,并且它可以从任何shell 调用,因此也可以从 PowerShell 调用。
相比之下,cmd确实有所谓的内部命令,确实只能从 调用cmd,例如mklink; 实际上,cmd您可以使用inwhere <name>来推断给定的(正在运行的)命令<name>是否是内部的:如果没有输出,则该命令是内部的(或根本不存在)。

或者,使用与cmdlet等效且更灵活的 PowerShell 对应where.exeGet-Command项;它返回System.Management.Automation.CommandInfo实例(或派生类的实例),其.Source属性包含表示外部可执行文件的命令信息对象的完整路径:

PS> (Get-Command git).Source
C:\Program Files\Git\cmd\git.exe

笔记:

  • where.exe仅查找可执行文件,而Get-Command默认查找所有命令类型(别名、函数、cmdlet、...) - 请参阅下一节。

  • 与, 不同Get-Commandwhere.exe还查找位于当前目录中的可执行文件。Get-Command不这样做,因为出于安全原因,PowerShell 在设计上不允许仅按名称调用位于当前目录中的可执行文件- 需要路径(例如,.\foo)。


PowerShell 有不同类型的命令,它们 - 在名称冲突的情况下 - 具有预定义的优先顺序,以确定哪种类型应该是有效的命令。

也就是说,如果给定的命令名称与两个或更多命令匹配,则它们的类型决定了实际调用哪个命令。

此优先级记录在概念about_Command_Precedence帮助主题中;简而言之,这是按类型降序排列的命令优先级(最高优先级在前):

  • 别名
  • 功能
  • cmdlet(松散地说:作为编译二进制文件实现的函数)
  • 外部可执行文件,包括*.ps1脚本文件 - 见底部

查看给定名称存在哪些命令类型-AllGet-Command的一种简单方法是在调用cmdlet时添加开关,该开关按优先级降序列出匹配的命令;也就是说,首先列出将通过给定名称实际执行的命令

PS> Get-Command -All where

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           where -> Where-Object
Application     where.exe                                          10.0.18... C:\WINDOWS\system32\where.exe

结果表明,cmdlet 的内置where别名Where-Object(其目的是过滤管道输入)是您提交时的有效命令where,而不是所需的where.exe可执行文件。

鉴于where.exe可执行文件名具有.exe可以将其与别名区分开来的扩展名,使用文件扩展名where调用是最简单where.exe 的,如顶部所示。

如果这是不可能的(例如,在类 Unix 平台上,可执行文件通常没有文件扩展名,或者如果别名隐藏了函数),您可以使用该-Type参数来获取感兴趣的命令,并调用它&呼叫运营商

# Invokes where.exe, as only it is of type 'Application' (external executable)
& (Get-Command -Type Application where) git

如果有多个基本文件名为 的外部可执行文件,它将执行最早where列出的目录中的那个 - 请参阅下一节。$env:PATH


外部可执行文件和*.ps1脚本之间的优先级:

笔记:

  • 与 PowerShell之间的一个重要区别cmd是 PowerShell - 出于安全原因的设计 -不允许您仅按名称.ps1调用位于当前目录中的外部可执行文件或脚本;为此,您必须使用path,在最简单的情况下通过前置(or ); 例如,要调用位于当前目录中的可执行文件,您必须使用.\./foo./foo ...

  • 实际上,脚本和其他可执行文件之间的优先级*.ps1因平台(Windows 与类 Unix 平台)而异,如下所述。

  • 下面的讨论假定给定的命令名称不会被优先级更高的命令类型(例如别名)所掩盖,并解析为外部可执行文件或*.ps1脚本。

优先规则:

  • 当命令名称通过环境变量中列出的目录解析为潜在的多个外部可执行文件或脚本时,将调用位于最早列出的目录中的可执行文件/脚本。*.ps1$env:PATH

  • 如果,在那个最早的目录中:

    • 定的名称与可执行文件名(例如where.exe)或脚本(例如foo.ps1完全匹配,没有歧义,并且调用了该可执行文件/脚本。

    • 给定的名称不包括文件扩展名(例如,foo),多个可执行文件可以匹配(通过隐含的文件扩展名),并且实际调用的文件确定如下:

      • Windows上:

        • PowerShell 优先考虑自己的脚本,因此如果存在.ps1脚本,则它是有效的命令;请注意,.ps1脚本是在进程内执行的,与外部可执行文件不同,后者总是在子进程中运行。

        • 否则,它是环境变量中的可执行扩展名中文件扩展名最早列出$env:PATHEXT的可执行文件;例如,foo.bat优先于foo.vbs,因为.BAT列在 之前.VBS

      • 类 Unix 平台(Linux、macOS)上:

        • 类 Unix 平台仅通过权限来确定可执行性,而不是通过文件扩展名,并且在绝大多数情况下,可执行文件没有文件扩展名(例如,只是git,不像git.exe在 Windows 上那样)。

        • 从 PowerShell 的角度来看,与 Unix 上的可执行性相关的唯一文件扩展名是.ps1,因为PowerShell 本身认为这些文件是可执行的——无论它们是否从系统的角度来看。

        • 因此,在 Unix 上的 PowerShell 中,.ps1唯一可以在调用时省略的隐含文件扩展名;例如,您可以直接调用脚本文件foo.ps1foo假设它在系统路径中)。

        • 如果您有一个外部可执行文件,其文件名没有文件扩展名 - 通常情况下 - 以及.ps1同一目录中具有相同基本名称的文件,则外部可执行文件优先 - 原因是扩展名 - less name与无扩展名的可执行文件名完全匹配。

          • 例如,如果外部可执行文件位于相同(最早的)目录中,则提交会调用外部可执行文件,这与 Windows 不同。foofoo.ps1foofoo.ps1

笔记:

  • 当使用显式路径(没有文件扩展名)时,给定目录中多个可执行文件之间的优先规则也适用;例如,调用./foo决定了当前目录中多个可执行文件之间的优先级,其基本名称foo如上所述。

  • .ps1脚本放置在列出的目录中$env:PATH并仅通过(基本)名称调用它们并不是很常见,尽管值得考虑将其作为在文件中放置潜在许多函数$PROFILE的替代方法。

    • 不幸的是,Linux上的 UX 很差,由于它区分大小写的文件系统,您必须在调用时指定(基本)文件名完全大小写,而 PowerShell 命令调用不区分大小写;例如,如果实际文件名是Get-Foo.ps1,则仅Get-Foo适用于调用,而不适用于get-foo.

[1] 至于为什么诸如where git- 即错误使用Where-Object- 之类的调用不会产生输出:调用Where-Object git相当于输出。Where-Object { $_.git }


推荐阅读