【问题标题】:Equivalent of *Nix 'which' command in PowerShell?等效于 PowerShell 中的 *Nix 'which' 命令?
【发布时间】:2010-09-08 23:50:13
【问题描述】:

如何询问 PowerShell 某物在哪里?

例如,“哪个记事本”,它会根据当前路径返回运行notepad.exe的目录。

【问题讨论】:

    标签: unix powershell command


    【解决方案1】:

    我喜欢Get-Command | Format-List,或者更短,对两者使用别名并且仅用于powershell.exe

    gcm powershell | fl
    

    你可以找到这样的别名:

    alias -definition Format-List
    

    制表符补全适用于gcm

    让选项卡一次列出所有选项:

    set-psreadlineoption -editmode emacs
    

    【讨论】:

      【解决方案2】:

      如果你有scoop,你可以安装一个直接克隆:

      scoop install which
      which notepad
      

      【讨论】:

        【解决方案3】:

        我的 PowerShell 配置文件中有这个 which 高级功能:

            function which {
            <#
            .SYNOPSIS
            Identifies the source of a PowerShell command.
            .DESCRIPTION
            Identifies the source of a PowerShell command. External commands (Applications) are identified by the path to the executable
            (which must be in the system PATH); cmdlets and functions are identified as such and the name of the module they are defined in
            provided; aliases are expanded and the source of the alias definition is returned.
            .INPUTS
            No inputs; you cannot pipe data to this function.
            .OUTPUTS
            .PARAMETER Name
            The name of the command to be identified.
            .EXAMPLE
            PS C:\Users\Smith\Documents> which Get-Command
            
            Get-Command: Cmdlet in module Microsoft.PowerShell.Core
            
            (Identifies type and source of command)
            .EXAMPLE
            PS C:\Users\Smith\Documents> which notepad
            
            C:\WINDOWS\SYSTEM32\notepad.exe
            
            (Indicates the full path of the executable)
            #>
                param(
                [String]$name
                )
            
                $cmd = Get-Command $name
                $redirect = $null
                switch ($cmd.CommandType) {
                    "Alias"          { "{0}: Alias for ({1})" -f $cmd.Name, (. { which $cmd.Definition } ) }
                    "Application"    { $cmd.Source }
                    "Cmdlet"         { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
                    "Function"       { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
                    "Workflow"       { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
                    "ExternalScript" { $cmd.Source }
                    default          { $cmd }
                }
            }
        

        【讨论】:

          【解决方案4】:

          您可以从https://goprogram.co.uk/software/commands 安装which 命令以及所有其他 UNIX 命令。

          【讨论】:

            【解决方案5】:

            与 Unix which 的快速匹配是

            New-Alias which where.exe
            

            但是如果它们存在,它会返回多行,那么它就变成了

            function which {where.exe command | select -first 1}
            

            【讨论】:

            • where.exe where 应该告诉你C:\Windows\System32\where.exe
            • where.exe 等同于which -a,因为它将返回所有匹配的可执行文件,而不仅仅是第一个要执行的可执行文件。也就是说,where.exe notepad 给出了c:\windows\notepad.exec:\windows\system32\notepad.exe。所以这特别适合$(which command)这个形式。 (另一个问题是,如果找不到该命令,它会打印一个很好的、有用的错误消息,它也不会在$() 中很好地扩展——这可以用/Q 补救,但不能作为别名。)
            • 点了。我编辑了答案,但是是的,它不再是一个很好的解决方案
            • 请注意,where 似乎在搜索系统 PATH 变量,而不是当前的 shell PATH 变量。见this question
            • function which {where.exe $args[0] | select -first 1} 会使其可重用。此外,posh 在处理路径、引号和空格方面似乎更可靠,因此function which {$(gcm $args[0]).source | select -first 1} 可能是更好的选择。
            【解决方案6】:

            如果您想要一个既可以接受来自管道的输入也可以作为参数的命令,您应该试试这个:

            function which($name) {
                if ($name) { $input = $name }
                Get-Command $input | Select-Object -ExpandProperty Path
            }
            

            将命令复制粘贴到您的个人资料 (notepad $profile)。

            例子:

            ❯ echo clang.exe | which
            C:\Program Files\LLVM\bin\clang.exe
            
            ❯ which clang.exe
            C:\Program Files\LLVM\bin\clang.exe
            

            【讨论】:

              【解决方案7】:

              我对Which函数的建议:

              function which($cmd) { get-command $cmd | % { $_.Path } }
              
              PS C:\> which devcon
              
              C:\local\code\bin\devcon.exe
              

              【讨论】:

              • 这是一个比公认的更好的答案。它允许您添加上面建议的后处理后缀以提供更好的输出;别名不会。
              【解决方案8】:

              用途:

              function Which([string] $cmd) {
                $path = (($Env:Path).Split(";") | Select -uniq | Where { $_.Length } | Where { Test-Path $_ } | Get-ChildItem -filter $cmd).FullName
                if ($path) { $path.ToString() }
              }
              
              # Check if Chocolatey is installed
              if (Which('cinst.bat')) {
                Write-Host "yes"
              } else {
                Write-Host "no"
              }
              

              还是这个版本,调用原来的where命令。

              这个版本也更好用,因为它不限于bat文件:

              function which([string] $cmd) {
                $where = iex $(Join-Path $env:SystemRoot "System32\where.exe $cmd 2>&1")
                $first = $($where -split '[\r\n]')
                if ($first.getType().BaseType.Name -eq 'Array') {
                  $first = $first[0]
                }
                if (Test-Path $first) {
                  $first
                }
              }
              
              # Check if Curl is installed
              if (which('curl')) {
                echo 'yes'
              } else {
                echo 'no'
              }
              

              【讨论】:

                【解决方案9】:

                在 Windows 2003 或更高版本(或 Windows 2000/XP,如果您已安装资源工具包)上尝试 where 命令。

                顺便说一句,这在其他问题中得到了更多答案:

                Is there an equivalent of 'which' on Windows?

                PowerShell equivalent to Unix which command?

                【讨论】:

                • where 是 Powershell 中 Where-Object 命令行开关的别名,因此在 Powershell 提示符下键入 where &lt;item&gt; 不会产生任何结果。因此,这个答案完全不正确 - 正如第一个链接问题中接受的答案所述,要获得 DOS where,您需要输入 where.exe &lt;item&gt;
                【解决方案10】:

                检查这个PowerShell Which

                那里提供的代码表明了这一点:

                ($Env:Path).Split(";") | Get-ChildItem -filter notepad.exe
                

                【讨论】:

                • 我知道已经过去好几年了,但我的路径有“%systemroot%\system32\...”,而 PowerShell 不会扩展该环境变量并在执行此操作时引发错误。
                【解决方案11】:

                这似乎可以满足您的需求(我在 http://huddledmasses.org/powershell-find-path/ 上找到了它):

                Function Find-Path($Path, [switch]$All = $false, [Microsoft.PowerShell.Commands.TestPathType]$type = "Any")
                ## You could comment out the function stuff and use it as a script instead, with this line:
                #param($Path, [switch]$All = $false, [Microsoft.PowerShell.Commands.TestPathType]$type = "Any")
                   if($(Test-Path $Path -Type $type)) {
                      return $path
                   } else {
                      [string[]]$paths = @($pwd);
                      $paths += "$pwd;$env:path".split(";")
                
                      $paths = Join-Path $paths $(Split-Path $Path -leaf) | ? { Test-Path $_ -Type $type }
                      if($paths.Length -gt 0) {
                         if($All) {
                            return $paths;
                         } else {
                            return $paths[0]
                         }
                      }
                   }
                   throw "Couldn't find a matching path of type $type"
                }
                Set-Alias find Find-Path
                

                【讨论】:

                • 但这并不是真正的“which”,因为它适用于任何文件(类型)并且找不到 cmdlet、函数或别名
                【解决方案12】:

                当我开始在 PowerShell 中自定义我的个人资料时,我创建的第一个别名是“which”。

                New-Alias which get-command
                

                要将其添加到您的个人资料中,请输入:

                "`nNew-Alias which get-command" | add-content $profile
                

                最后一行开头的`n是为了确保它将作为新行开始。

                【讨论】:

                • 您可以将其放入您的配置文件脚本中。更多关于个人资料 - msdn.microsoft.com/en-us/library/bb613488(VS.85).aspx
                • 我喜欢运行:Get-Command &lt;command&gt; | Format-Table Path, Name,所以我也可以获取命令所在的路径。
                • 有没有什么办法让路径一直没有输入'|格式表路径,名称'?
                • 如果您想要 Unix 风格的行为,即为您提供路径,您需要将 get-command 的输出通过管道传输到 select -expandproperty Path
                • 使用(gcm &lt;command&gt;).definition 仅获取路径。 gcmGet-Command 的默认别名。您还可以使用通配符,例如:(gcm win*.exe).definition
                【解决方案13】:

                试试这个例子:

                (Get-Command notepad.exe).Path
                

                【讨论】:

                • 请添加更多代码或解释,以便 OP 更好地理解您。谢谢。
                • 感谢您添加了更少的代码,所以我实际上可以记住一次:P
                • 这就是我想要的!它也适用于 gcm:(gcm py.exe).path
                【解决方案14】:

                这是一个实际的 *nix 等价物,即它提供 *nix 样式的输出。

                Get-Command <your command> | Select-Object -ExpandProperty Definition
                

                只需替换为您要查找的任何内容。

                PS C:\> Get-Command notepad.exe | Select-Object -ExpandProperty Definition
                C:\Windows\system32\notepad.exe
                

                当您将其添加到您的个人资料时,您将希望使用函数而不是别名,因为您不能将别名与管道一起使用:

                function which($name)
                {
                    Get-Command $name | Select-Object -ExpandProperty Definition
                }
                

                现在,当您重新加载您的个人资料时,您可以这样做:

                PS C:\> which notepad
                C:\Windows\system32\notepad.exe
                

                【讨论】:

                • 我使用这种替代语法:“(Get-Command notepad).definition”
                • @B00merang 您的语法很棒--绝对更简洁--但不幸的是,即使删除了管道,也不能将其添加为别名,除非您包含您正在查找的程序的名称为。
                • 这是一篇旧帖子,但如果有人被谷歌发送到这里(就像我一样),这个答案适用于比接受的答案更多类型的 Powershell 命令。例如,我有一个名为 okta 的别名,它指向一个名为 okta.ps1 的 Powershell 脚本,它不在我的 $PATH 上。使用接受的答案返回脚本名称 (okta -&gt; okta.ps1)。这没关系,但它没有告诉我okta.ps1 的位置。然而,使用这个答案给了我整个路径(C:\Users\blah\etc\scripts\okta.ps1)。所以我要 +1。
                【解决方案15】:

                我通常只输入:

                gcm notepad
                

                gcm note*
                

                gcm 是 Get-Command 的默认别名。

                在我的系统上,gcm note* 输出:

                [27] » gcm note*
                
                CommandType     Name                                                     Definition
                -----------     ----                                                     ----------
                Application     notepad.exe                                              C:\WINDOWS\notepad.exe
                Application     notepad.exe                                              C:\WINDOWS\system32\notepad.exe
                Application     Notepad2.exe                                             C:\Utils\Notepad2.exe
                Application     Notepad2.ini                                             C:\Utils\Notepad2.ini
                

                您将获得与您要查找的内容相匹配的目录和命令。

                【讨论】:

                • 它有点乱,但比自定义函数和任意拆分更干净
                • 当我在我的 powershell 命令提示符中键入“gcm notepad”时,我只得到前两列,第三列名为“ModuleName”,它是空的。你知道如何强制它默认列出“定义”列吗?
                • @PiyushSoni 这可能是因为 PowerShell 的更新版本。您始终可以通过执行gcm note* | select CommandType, Name, Definition 之类的操作来显示其他列。不过,如果你经常运行它,你可能应该将它包装在一个函数中。
                猜你喜欢
                • 2012-09-01
                • 2011-12-26
                • 2016-10-02
                • 2018-01-15
                • 1970-01-01
                • 2019-08-16
                • 1970-01-01
                • 2012-04-10
                相关资源
                最近更新 更多