Home > Blockchain >  Which executable is run by DOS/CMD if multiple results are returned by 'where'?
Which executable is run by DOS/CMD if multiple results are returned by 'where'?

Time:05-21

I'm running Win10, with Cygwin, Git for Windows and Ubuntu WSL installed.
Running these commands in DOS and Powershell returns the following results:

# DOS
C:\>where grep
C:\cygwin64\bin\grep.exe
C:\Program Files\Git\usr\bin\grep.exe

# DOS
C:\>which grep
/usr/bin/grep

# Powershell
C:\> gcm grep*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     grep.exe                                           0.0.0.0    C:\cygwin64\bin\grep.exe
Application     grep.exe                                           0.0.0.0    C:\Program Files\Git\usr\bin\grep.exe

Now when I run this, which one of the above actually runs?

# DOS / Powershell
C:\>grep ... ---> ?

Is it run in the order they appear here, or are listed in PATH environment variable? Or another order (which one)?

CodePudding user response:

Terminology aside: I assume you mean cmd.exe aka the Command Prompt, the command shell of modern Windows versions, not the long-obsolete (MS-)DOS and its command.com counterpart.

Is it run in the order they appear here, or are listed in PATH environment variable? Or another order (which one)?

Yes, the first executable whose path is listed in the results from your calls is the one that will be called if you submit grep, i.e. a mere file name, as a command.

However, note that you should have called gcm grep, not gcm grep*, in which you'd have received only one result, because Get-Command (whose built-in alias is gcm), when given a literal name (rather than a wildcard expression), only returns the effective form / path of that command by default, as the Unix which utility does.

Both Get-Command and which require opt-in if you want to know all forms / paths of a given name, namely via -All and -a, respectively, in which case they are listed in descending order of precedence, i.e. with the effective one printing first.

where.exe, by contrast, invariably prints all paths, in descending order of precedence.

Among external programs - which are the only command form considered by which and where.exe - it is the order in which directories are listed in the PATH environment variable that determines precedence: an executable with a given name is looked for sequentially in the directories listed, and the first one found is the effective one.

On Windows, if no file-name extension is given, it is the extensions listed in the PATHEXT environment variable that are applied in sequence to look for a complete file name, so that grep finds grep.exe, for instance.

Get-Command by default additionally looks for PowerShell-specific command forms, in the form of aliases, functions, cmdlets, as well as .ps1 script files, in that order, before considering external programs. You can limit lookups to external programs with -Type Application, but note that on invocation you may have to include the filename extension in order to bypass another command form that would otherwise take precedence.
For instance, where would find / invoke the Where-Object cmdlet (one of whose built-in aliases is where), whereas where.exe would find / invoke the external program. On Unix-like platforms, where external programs typically don't have extensions, more work is needed on invocation; e.g., to invoke a hypothetical where program without accidentally invoking the Where-Object cmdlet, you'd have to use
& (Get-Command -Type Application where)

Note that the same applies in principle to cmd.exe and POSIX-compatible shells: they too have internal commands that can shadow external programs of the same name (e.g., dir in cmd.exe, and printf in Bash); in cmd.exe, you can again use the executable's file-name extension to ensure that the external program is targeted; in POSIX-compatible shells, you can call via $(which printf), for instance.

In short: Only Get-Command in PowerShell gives you the full picture with respect to what a command a given name will actually invoke; the where.exe and which utilities - of necessity - are limited to external programs.

Finally, as Mofi notes, there is an important difference between cmd.exe on the one hand and PowerShell and POSIX-compatible shells on the other:

  • Only cmd.exe allows you to execute an external program located in the current directory by name only.

  • By security-minded design, PowerShell and POSIX-compatible shells do not support that, and require a path to refer to the program in this case; in the simplest form: .\foo.exe / ./foo.

  • where.exe does report executables in the current directory, so if you call it from PowerShell, you may get a false positive; that said, given the availability of the more flexible Get-Command cmdlet, there's no good reason to call where.exe from PowerShell.

  • Related