Entspricht dem Befehl * Nix 'which' in PowerShell?

404

Wie frage ich PowerShell, wo sich etwas befindet?

Beispiel: "welcher Notizblock" und es wird das Verzeichnis zurückgegeben, in dem die Datei notepad.exe gemäß den aktuellen Pfaden ausgeführt wird.

Entwicklung von Chris
quelle

Antworten:

391

Der allererste Alias, den ich erstellt habe, als ich anfing, mein Profil in PowerShell anzupassen, war "welcher".

New-Alias which get-command

Geben Sie Folgendes ein, um dies Ihrem Profil hinzuzufügen:

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

Das `n am Anfang der letzten Zeile soll sicherstellen, dass es als neue Zeile beginnt.

halr9000
quelle
1
Sie können es in Ihr Profilskript einfügen. Mehr zu Profilen - msdn.microsoft.com/en-us/library/bb613488(VS.85).aspx
Steven Murawski
62
Ich laufe gern: Get-Command <command> | Format-Table Path, Namedamit ich den Pfad bekomme, auf dem sich auch der Befehl befindet.
jrsconfitto
4
Gibt es eine Möglichkeit, den Pfad ständig zu haben, ohne '| eingeben zu müssen? Format-Tabellenpfad, Name '?
Guillaume
10
Wenn Sie das Unix-Verhalten wünschen, das Ihnen den Pfad gibt, müssen Sie die Ausgabe von get-command an weiterleiten select -expandproperty Path.
Casey
5
Verwenden Sie (gcm <command>).definitiondiese Option , um nur die Pfade abzurufen. gcmist der Standardalias für Get-Command. Sie können auch Platzhalter verwenden, z (gcm win*.exe).definition.
Sachin Joseph
165

Hier ist ein tatsächliches * nix-Äquivalent, dh es gibt eine Ausgabe im * nix-Stil.

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

Ersetzen Sie einfach durch das, was Sie suchen.

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

Wenn Sie es Ihrem Profil hinzufügen, möchten Sie eine Funktion anstelle eines Alias ​​verwenden, da Sie keine Aliase mit Pipes verwenden können:

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

Wenn Sie jetzt Ihr Profil neu laden, können Sie Folgendes tun:

PS C:\> which notepad
C:\Windows\system32\notepad.exe
petrsnd
quelle
22
Ich benutze diese alternative Syntax: "(Get-Command Notepad) .definition"
Yann
2
@ B00merang Ihre Syntax ist großartig - definitiv prägnanter - aber leider kann sie auch ohne entfernte Pipe nicht als Alias ​​hinzugefügt werden, es sei denn, Sie geben den Namen des gesuchten Programms an.
Petrsnd
4
Dies ist ein alter Beitrag, aber falls jemand von Google hierher geschickt wird (wie ich), funktioniert diese Antwort mit mehr Arten von Powershell-Befehlen als die akzeptierte Antwort. Ich habe beispielsweise einen Alias ​​mit dem Namen okta, der auf ein Powershell-Skript mit dem Namen verweist, okta.ps1das sich nicht in meinem befindet $PATH. Bei Verwendung der akzeptierten Antwort wird der Skriptname ( okta -> okta.ps1) zurückgegeben. Dies ist in Ordnung, aber es sagt mir nicht den Standort von okta.ps1. Die Verwendung dieser Antwort gibt mir jedoch den gesamten Pfad ( C:\Users\blah\etc\scripts\okta.ps1). Also +1 von mir.
Skye --- Kapitän
88

Normalerweise tippe ich einfach:

gcm notepad

oder

gcm note*

gcm ist der Standardalias für Get-Command.

Auf meinem System gibt gcm note * Folgendes aus:

[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

Sie erhalten das Verzeichnis und den Befehl, die dem entsprechen, wonach Sie suchen.

David Mohundro
quelle
Es ist ein bisschen chaotisch, aber viel sauberer als benutzerdefinierte Funktionen und willkürliche Aufteilungen
DevelopingChris
1
Wenn ich "gcm notepad" in meine Powershell-Eingabeaufforderung eingebe, erhalte ich nur die ersten beiden Spalten und eine dritte Spalte namens "ModuleName", die leer ist. Wissen Sie, wie Sie es erzwingen können, die Spalte 'Definition' standardmäßig aufzulisten?
Piyush Soni
3
@PiyushSoni Das liegt wahrscheinlich an einer aktualisierten Version von PowerShell. Sie können die anderen Spalten jederzeit anzeigen, indem Sie so etwas tun gcm note* | select CommandType, Name, Definition. Wenn Sie es häufig ausführen, sollten Sie es wahrscheinlich in eine Funktion einschließen.
David Mohundro
40

Versuchen Sie dieses Beispiel:

(Get-Command notepad.exe).Path
thesqldev
quelle
2
Bitte fügen Sie mehr Code oder Erklärungen hinzu, damit das OP Sie besser verstehen kann. Vielen Dank.
sshashank124
3
Vielen Dank, dass Sie weniger Code hinzugefügt haben, damit ich mich einmal daran erinnern kann: P
Albertjan
1
Das wollte ich! Es funktioniert auch mit gcm:(gcm py.exe).path
Bill Agee
7

Mein Vorschlag für die Welche Funktion:

function which($cmd) { get-command $cmd | % { $_.Path } }

PS C:\> which devcon

C:\local\code\bin\devcon.exe
VortiFred
quelle
Dies ist eine bessere Antwort als die akzeptierte. Sie können die oben vorgeschlagenen Nachbearbeitungssuffixe hinzufügen, um eine bessere Ausgabe zu erzielen. ein Alias ​​nicht.
BobHy
5

Eine schnelle und schmutzige Übereinstimmung mit Unix whichist

New-Alias which where.exe

Es werden jedoch mehrere Zeilen zurückgegeben, wenn sie vorhanden sind

function which {where.exe command | select -first 1}
Chris F. Carroll
quelle
1
where.exe wheresollte Ihnen sagenC:\Windows\System32\where.exe
Chris F Carroll
1
where.exeist gleichbedeutend mit which -a, da alle übereinstimmenden ausführbaren Dateien zurückgegeben werden, nicht nur die erste, die ausgeführt wird. Das heißt, where.exe notepadgibt c:\windows\notepad.exeund c:\windows\system32\notepad.exe. Das ist also besonders für die Form nicht geeignet $(which command). (Ein weiteres Problem ist, dass eine nette, hilfreiche Fehlermeldung ausgegeben wird, wenn der Befehl nicht gefunden wird, die auch nicht gut erweitert wird $()- das kann behoben werden /Q, aber nicht als Alias.)
Jeroen Mostert
Punkt genommen. Ich habe die Antwort bearbeitet, aber ja, es ist keine so saubere Lösung mehr
Chris F Carroll
1
Bitte beachten Sie, dass whereanscheinend die System-PATH-Variable und nicht die aktuelle Shell-PATH-Variable durchsucht wird. Siehe diese Frage
Leonardo
3

Dies scheint zu tun, was Sie wollen (ich fand es auf 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
Nikolaus
quelle
Aber es ist nicht wirklich "was", da es mit jeder Datei (Typ) funktioniert und keine Cmdlets, Funktionen oder Aliase findet
Jaykul
3

Überprüfen Sie diese PowerShell Welche .

Der dort bereitgestellte Code schlägt Folgendes vor:

($Env:Path).Split(";") | Get-ChildItem -filter notepad.exe
tzot
quelle
2
Ich weiß, dass es Jahre her ist, aber mein Pfad hatte "% systemroot% \ system32 \ ..." und PowerShell erweitert diese Umgebungsvariable nicht und löst dabei Fehler aus.
TessellatingHeckler
3

Ich mag Get-Command | Format-Listoder kürzer, Aliase für die beiden zu verwenden und nur für powershell.exe:

gcm powershell | fl

Sie können Aliase wie diese finden:

alias -definition Format-List

Die Tab-Vervollständigung funktioniert mit gcm .

js2010
quelle
2

Probieren Sie die where Befehl unter Windows 2003 oder höher (oder Windows 2000 / XP, wenn Sie ein Resource Kit installiert haben).

Übrigens erhielt dies mehr Antworten in anderen Fragen:

Gibt es ein Äquivalent zu 'which' unter Windows?

PowerShell entspricht dem Unix- whichBefehl?

Anonym
quelle
4
whereAliase für das Where-ObjectCommandlet in Powershell. Wenn Sie also where <item>eine Powershell-Eingabeaufforderung eingeben, erhalten Sie nichts. Diese Antwort ist daher völlig falsch - wie in der akzeptierten Antwort in der ersten verknüpften Frage angegeben, wheremüssen Sie eingeben , um das DOS zu erhalten where.exe <item>.
Ian Kemp
0

Ich habe diese whicherweiterte Funktion in meinem PowerShell-Profil:

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 }
    }
}
Jeff Zeitlin
quelle
0

Verwenden:

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"
}

Oder diese Version, die den ursprünglichen where-Befehl aufruft.

Diese Version funktioniert auch besser, da sie nicht auf Fledermausdateien beschränkt ist:

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'
}
Hieronymus
quelle
0

Wenn Sie ein Kommando wünschen, das sowohl Eingaben aus der Pipeline als auch als Parameter akzeptiert, sollten Sie Folgendes versuchen:

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

Kopieren Sie den Befehl und fügen Sie ihn in Ihr Profil ein ( notepad $profile).

Beispiele:

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

 which clang.exe
C:\Program Files\LLVM\bin\clang.exe
Amin
quelle