【发布时间】:2020-06-08 20:19:43
【问题描述】:
PowerShell 可以使用命令“git”,我想知道我的 PC 上安装了 git 的位置,所以我尝试执行这样的“脚本”
PS> where git
但执行后我什么也看不到,只提示输入新命令。 问题:如何在 Windows 10 中找到命令路径?
【问题讨论】:
-
$(get-command git).Path
标签: windows git powershell
PowerShell 可以使用命令“git”,我想知道我的 PC 上安装了 git 的位置,所以我尝试执行这样的“脚本”
PS> where git
但执行后我什么也看不到,只提示输入新命令。 问题:如何在 Windows 10 中找到命令路径?
【问题讨论】:
$(get-command git).Path
标签: windows git powershell
现有的答案很有帮助,但我认为更系统的讨论也有帮助。
tl;dr
where 是Where-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 帮助主题中;简而言之,这是按类型降序排列的命令优先级(最高优先级在前):
*.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> 优先 - 原因是无扩展名的名称与无扩展名的可执行文件名完全匹配。
foo 和 foo.ps1 位于同一个(最早的)目录中,则提交 foo 会调用 外部可执行文件,而不是 foo.ps1 - 不像在 Windows 上。
注意:
当使用显式路径(没有文件扩展名)时,给定目录中多个可执行文件之间的优先规则也适用;例如,如上所述,调用./foo 决定了当前目录中base 名称为foo 的多个可执行文件的优先级。
将.ps1 脚本放置在$env:PATH 中列出的目录中并仅通过(基本)名称调用它们并不是很常见,尽管它值得考虑作为放置潜在许多函数的替代方法 em> 在一个人的$PROFILE 文件中。
Get-Foo.ps1,则只有 Get-Foo 可用于调用,而不是 get-foo。[1] 至于为什么像where git这样的调用 - 即错误使用Where-Object - 不会产生输出:该调用相当于Where-Object git,而后者又相当于@ 987654415@,在没有 管道输入 到 cmdlet 的定义下,它永远不会产生输出。
【讨论】:
用途:
$(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 无关。
在 Powershell 中,where 是 where-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。