【问题标题】:Where is program's path for PowerShell command?PowerShell 命令的程序路径在哪里?
【发布时间】:2020-06-08 20:19:43
【问题描述】:

PowerShell 可以使用命令“git”,我想知道我的 PC 上安装了 git 的位置,所以我尝试执行这样的“脚本”

PS> where git

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

【问题讨论】:

  • $(get-command git).Path

标签: windows git powershell


【解决方案1】:

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

tl;dr

whereWhere-Object cmdlet 的PowerShell 内置别名;要调用外部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 自带的外部可执行文件,可以从any调用em> shell,因此也来自 PowerShell。
相比之下,cmd 确实有所谓的internal 命令,确实只能从cmd 调用,例如mklink;事实上,在cmd 中,您可以使用where <name> 来推断给定的(正在运行的)命令<name> 是否为内部命令:如果没有输出,则该命令为内部(或根本不存在)。

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

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

注意:

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

  • Get-Command 不同,where.exe 还可以查找位于 当前 目录中的可执行文件。 Get-Command 不会这样做,因为出于安全原因,PowerShell 在设计上不允许通过 name only 调用位于当前目录中的可执行文件 - path 是必需(例如,.\foo)。


PowerShell 有不同的类型命令,它们 - 在名称冲突的情况下 - 有一个预定义的优先顺序来确定什么类型应该是有效的命令。

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

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

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

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

PS> Get-Command -All where

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

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

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

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

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

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


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

注意:

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

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

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

优先规则:

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

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

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

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

      • Windows上:

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

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

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

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

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

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

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

          • 例如,如果外部可执行文件 foofoo.ps1 位于同一个(最早的)目录中,则提交 foo 会调用 外部可执行文件,而不是 foo.ps1 - 不像在 Windows 上。

注意:

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

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

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

[1] 至于为什么像where git这样的调用 - 即错误使用Where-Object - 不会产生输出:该调用相当于Where-Object git,而后者又相当于@ 987654415@,在没有 管道输入 到 cmdlet 的定义下,它永远不会产生输出。

【讨论】:

    【解决方案2】:

    用途:

    $(get-command <command name>).path
    

    $(get-command <command name>).source
    

    或者在你的情况下

    $(get-command git).path
    

    $(get-command git).source
    

    get-command 获取 cmdlet 信息,并且有一个 source 参数,因此如果您使用 get-command 作为变量,则可以访问 cmdlet 的路径。

    你也可以在powershell中使用cmd版本

    cmd /c "where git"
    

    【讨论】:

    • 有帮助,但请注意,没有理由使用 $(...),这是不必要的,并且可能会产生副作用 - 只需使用 (...) - 请参阅 stackoverflow.com/a/58248195/45375。另外,where.exe git 可以;外部的where.exe 可执行文件与cmd 无关。
    【解决方案3】:

    在 Powershell 中,wherewhere-object 的别名,用于过滤集合。

    Get-Alias -Name where                                                                
    CommandType     Name                          Version    Source
    -----------     ----                          -------    ------
    Alias           where -> Where-Object
    

    在 Cmd 中,where 显示文件的位置。

    Cmd 的 where 的 Powershell 版本是 Get-Command

    Get-Command -Name git
    CommandType     Name                        Version    Source
    -----------     ----                        -------    ------
    Application     git.exe                     2.20.1.1   C:\Program Files\Git\cmd\git.exe
    

    【讨论】:

    • 有帮助,但请注意 where.exe - 一个外部可执行文件 - 与 cmd 无关,您可以通过包含文件扩展名从 PowerShell 调用它:where.exe git
    猜你喜欢
    • 1970-01-01
    • 2014-07-15
    • 2016-12-11
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    • 2011-09-05
    • 2016-09-04
    相关资源
    最近更新 更多