Command 'git' is available from PowerShell, I want to know where is git installed on my PC, so I tried to execute such 'script'
PS> where git
but after execution I see nothing, only prompt for new command. Question: How can I find path for command in Windows 10?
The existing answers are helpful, but I think a more systematic discussion is helpful too.
tl;dr
where
is PowerShell's built-in alias for the Where-Object
cmdlet; to invoke the external where.exe
program , use .exe
explicitly: [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
, whose purpose is return the full path of an executable in the system's path (in one of the directories listed in the $env:PATH
environment variable), is unrelated to cmd
(the legacy command processor): it is an external executable that comes with Windows, and it can be invoked from any shell, and therefore also from PowerShell.
By contrast, cmd
does have so-called internal commands that indeed can only be called from cmd
, such as mklink
; in fact, in cmd
you can use where <name>
to infer whether a given (functioning) command <name>
is internal or not: if there's no output , the command is internal (or doesn't exist at all).
Alternatively , use the equivalent and more flexible PowerShell counterpart to where.exe
, the Get-Command
cmdlet ; it returns System.Management.Automation.CommandInfo
instances (or instances of derived classes), whose .Source
property contains the full path for a command-info object representing an external executable:
PS> (Get-Command git).Source
C:\Program Files\Git\cmd\git.exe
Note:
where.exe
finds only executable files , whereas Get-Command
by default looks for all command types (aliases, functions, cmdlets, ...) - see next section.
Unlike Get-Command
, where.exe
also finds executables located in the current directory. Get-Command
doesn't do that, because PowerShell by design, for security reasons, doesn't allow calling executables located in the current directory by name only - a path is required (eg, .\foo
).
PowerShell has different types of commands, which - in the case of name conflicts - have a predefined order of precedence to determine what type should be the effective command.
That is, if a given command name matches two or more commands, it is their type that determines which command is actually invoked.
This precedence is documented in the conceptual about_Command_Precedence
help topic; in short, here is the command precedence by type in descending order (highest precedence first):
*.ps1
script files - see bottom sectionAn easy way to see what command types exist for a given name is to add the -All
switch when calling the Get-Command
cmdlet , which lists the matching commands in descending order of precedence; that is, the command that will actually be executed via the given name is listed first .
PS> Get-Command -All where
CommandType Name Version Source
----------- ---- ------- ------
Alias where -> Where-Object
Application where.exe 10.0.18... C:\WINDOWS\system32\where.exe
The result shows that the built-in where
alias for the Where-Object
cmdlet (whose purpose is to filter pipeline input) is the effective command when you submit where
, and not the desired where.exe
executable.
Given that the where.exe
executable file name has the .exe
extension that can distinguish it from the where
alias, it is simplest to invoke where.exe
with the filename extension , as shown at the top.
In cases where this is not possible (eg, on Unix-like platforms, where executables typically do not have a filename extension or if an alias shadows a function), you can use the -Type
parameter to get the command of interest, and invoke it with &
, the call operator :
# Invokes where.exe, as only it is of type 'Application' (external executable)
& (Get-Command -Type Application where) git
Should there be multiple external executables whose base file name is where
, it is the one from the directory listed earliest in $env:PATH
that will be executed - see next section.
*.ps1
scripts:Note:
One important difference between cmd
and PowerShell is that PowerShell - by design, for security reasons - does not allow you to invoke an external executable or .ps1
script located in the current directory by name only; to do so, you must use a path , in the simplest case by prepending .\
(or ./
); eg, to invoke an executable foo
located in the current directory, you must use ./foo...
The precedence between *.ps1
scripts and other executables in effect differs by platform (Windows vs. Unix-like platforms), as detailed below.
The following discussion assumes that a given command name isn't shadowed by higher-precedence command types, such as aliases, and resolves to an external executable or *.ps1
script.
Precedence rules:
When a command name resolves to potentially multiple external executables or *.ps1
scripts via the directories listed in the $env:PATH
environment variable, the executable / script located in the directory that is listed earliest is invoked .
If, in that earliest directory:
the given name exactly matches an executable file name (eg, where.exe
) or script (eg, foo.ps1
), there is no ambiguity , and that executable / script is invoked.
the given name doesn't include a filename extension (eg, foo
), multiple executables can match (via implied filename extensions), and the one to actually invoke is determined as follows:
On Windows :
PowerShell gives precedence to its own scripts , so if a .ps1
script is present, it is the effective command ; note that .ps1
scripts are executed in-process , unlike external executables, which invariably run in a child process .
Otherwise, it is the executable file whose filename extension is listed earliest among the executable extensions in the $env:PATHEXT
environment variable ; eg, foo.bat
takes precedence over foo.vbs
, because, .BAT
is listed before .VBS
.
On Unix-like platforms (Linux, macOS):
Unix-like platforms determine executability solely via permissions , not via filename extensions, and executables in the vast majority of cases have no filename extension (eg, just git
, not git.exe
as on Windows).
From PowerShell's perspective, the only filename extension that matters with respect to executability on Unix is .ps1
, because it is PowerShell itself that considers such files executable - irrespective of whether they are from the system 's perspective.
Therefore, in PowerShell on Unix, .ps1
is the only implied filename extension that can be omitted on invocation ; eg, you can invoke a script file foo.ps1
as just foo
(assuming it is in the system's path).
If you have an external executable whose file name doesn't have a filename extension - as is typical - and a .ps1
file with the same base name in the same directory, it is the external executable that takes precedence - the reason is that the extension-less name is an exact match for the extension-less executable file name.
foo
and foo.ps1
are located in the same (earliest) directory, submitting foo
invokes the external executable , not foo.ps1
- unlike on Windows.Note:
The precedence rules among multiple executables in a given directory also apply when using an explicit path (without a filename extension); eg, invoking ./foo
decides the precedence among multiple executables in the current directory whose base name is foo
as described above.
Placing .ps1
scripts in a directory listed in $env:PATH
and invoking them by (base) name only isn't all that common, although it is worth considering as an alternative to putting potentially many functions in one's $PROFILE
file.
Get-Foo.ps1
, only Get-Foo
works for invocation, not get-foo
. [1] As for why a call such as where git
- ie mistaken use of Where-Object
- doesn't produce output: The call is equivalent to Where-Object git
, which is in turn equivalent to Where-Object { $_.git }
, which, in the absence of pipeline input to the cmdlet by definition never produces output.
In Powershell, where
is an alias for where-object
, which is used to filter collections.
Get-Alias -Name where
CommandType Name Version Source
----------- ---- ------- ------
Alias where -> Where-Object
In Cmd, where displays location of files.
The Powershell version of Cmd's where
is Get-Command
Get-Command -Name git
CommandType Name Version Source
----------- ---- ------- ------
Application git.exe 2.20.1.1 C:\Program Files\Git\cmd\git.exe
Use:
$(get-command <command name>).path
or
$(get-command <command name>).source
or in your case
$(get-command git).path
or
$(get-command git).source
get-command
gets cmdlet info and there is a source
parameter so if you use get-command
as a variable, you can access the path of the cmdlet.
You can also use the cmd version in powershell with
cmd /c "where git"
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.