Here I am presenting a couple of tools dealing with displaying the access to DOS programs in light of the operating system search order.
Questions that have or may be answered here may be of some educational interest to those new to the topic.
- IsItDOS.bat The code has been moved to this post. This utility accepts a string and attempts to determine if such a command exists, its location, and classifies it as a command, System or built-in DOS command.
- PathFinder.batThis utility does a more comprehensive search to list all instances in precedence along the actual or proposed search path as well as invoking IsItDOS to add system if it applies. The code below has been replaced with the latest version.
- These routines have been tested on Win XP and provide a limited (wildcards are missing) 'where' command which does not exist on XP. There is an option to turn off 'How am I doing' messages to simulate 'where' output.
Code: Select all
:IsitDOS cmd -- Determine if a string is a DOS system command
:: -- cmd [in] - Command name with no extension
::Returns -- errorlevel: 0 if DOS builtin or system command, 1 if not
::
@Echo Off &SetLOCAL EnableDelayedExpansion &Rem.and keep environment uncluttered.
If "%~1"=="" Echo.&Echo.IsItDOS [-h][/?] CmdName [-h][/?]
If "%~1"=="" Echo.Command name is required. Terminating [rc=1] . . .&Exit /B 1
If /I "%~1"=="-h" Echo.&Echo.Syntax: IsItDOS [-h][/?] CmdName [-h][/?] - Terminating [rc=01] . . .&Exit /B 1
If /I "%~2"=="-h" Echo.&Echo.Syntax: IsItDOS [-h][/?] CmdName [-h][/?] - Terminating [rc=01] . . .&Exit /B 1
If "%~1"=="/?" Echo.&Echo.Determine if a string is a DOS builtin or System command.
If "%~1"=="/?" Echo.&Echo.IsItDOS [-h][/?] CmdName [-h][/?] - Terminating [rc=01] . . .&Exit /B 1
If "%~2"=="/?" Echo.&Echo.IsItDOS [-h][/?] CmdName [-h][/?] - Terminating [rc=01] . . .&Exit /B 1
Rem.DOS Testing Environment '0' easy to find temporary folder
Set "tmpd=%TEMP%\'0'"
If Not Exist "%tmpd%" MkDir "%tmpd%"
:: Following command terminates batch script if exists and may produce bad output
:: >%tmpd%\%~n0.txt %~1 /? 2>nul
:: Above command is coaxed to run on its own so as not to end this one
>"%tmpd%\%~n0.cmd" (
Echo.@Echo Off
Echo.SetLOCAL EnableEXTENSIONS
Echo.%~1 /?
)
2>nul Call "%tmpd%\%~n0.cmd" >"%tmpd%\%~n0.txt"
@Echo Off&Rem.Previous Call command leaves Echo On
2>nul (
FOR /F "UseBackQ tokens=1-4,5* " %%i in (`DIR "%tmpd%\%~n0.txt" /A:-S-d /-C /S`) do (
IF "File(s)"=="%%j" set resultuse=%%k
)
)
If "%resultuse%"=="" (Set "resultuse=0")
If %resultuse%==0 (
Set "IsItDOSrc=1"
)
>"%tmpd%\%~n0_Help.cmd" (
Echo.@Echo Off
Echo.SetLOCAL EnableEXTENSIONS
Echo.HELP
)
2>nul Call "%tmpd%\%~n0_Help.cmd" >"%tmpd%\%~n0_Help.txt"
For /F %%H in ('findstr /I /L /C:"%~1" "%tmpd%\%~n0_Help.txt"') do (
If /I .%%H EQU .%~1 Set "Helped=%%H"
)
If /I .%Helped% EQU .%~1 (
If /I "%~2" NEQ "-q" (Echo.
Echo.Crosschecking with general System HELP for '!Helped!' was positive.
)
Set "resultuse=1"
)
If %resultuse%==0 (
If /I "%~2" NEQ "-q" (
Echo.
Echo.'%~1' produced no HELP output, failing a DOS builtin command check.
)
Echo.
Echo.'%~1' appears NOT to be a DOS builtin or System command.
) Else (
If /I "%~2" NEQ "-q" (
Echo.
Echo.'%~1' responds during DOS builtin command check for any help output.
)
If Defined Helped (
Set "IsItDOSrc=0"
) Else (
set /a counter=1
Set "IsItDOSrc=1"
FOR /F "usebackq tokens=1* " %%i in ("%tmpd%\%~n0.txt") do (
set /a counter+=1
IF /I "%~1"=="%%i" (
IF "!counter!" LEQ "4" Set "IsItDOSrc=0"
)
IF "!counter!" GEQ "5" GoTo foundDOS
)
)
:FoundDOS
If "!IsItDOSrc!"=="1" Echo.'%~1' Appears NOT to be a DOS builtin command.
)
SET ComSpecDir=%ComSpec:\cmd.exe=%
Call :AnyPath %~1
If "%IsItDOSrc%"=="0" (
If Exist %ComSpecDir%\%~1.exe (
Echo.'%~1.exe' is a DOS system command in '%ComSpecDir%'.
If Defined AnyName (
If /I %ComSpecDir%\%~1.exe NEQ !AnyName! (
Echo.and has been pre-empted by '!LongName!'.
)
)
) Else (
If Exist %ComSpecDir%\%~1.com (
Echo.'%~1.com' is a DOS system command in '%ComSpecDir%'.
If Defined AnyName (
If /I %ComSpecDir%\%~1.com NEQ !AnyName! (
Echo.and has been pre-empted by '!LongName!'.
)
)
) Else (
If Defined AnyName (
Set "IsItDOSrc=1"
If /I "%~2" NEQ "-q" (
Echo.'%~1' produced Help output in a format consistent with a DOS command.
)
If Defined Helped (
Set "IsItDOSrc=0"
Echo.'%~1' appears to be built into the DOS command interpreter.
Echo.and has been pre-empted by '!LongName!'.
) Else (
Echo.'%~1' appears NOT to be a DOS builtin or System command.
Echo.but was found as '!LongName!'.
)
) Else (
Echo.'%~1' appears to be built into the DOS command interpreter.
)
)
rem.
)
) Else (
If Defined AnyName Echo.first encountered as !LongName!.
)
set Name=
set AnyName=
set LongName=
Del "%tmpd%\%~n0.cmd"
Del "%tmpd%\%~n0.txt"
Del "%tmpd%\%~n0_Help.cmd"
Del "%tmpd%\%~n0_Help.txt"
Exit /B %IsItDOSrc%
:AnyPath
@echo off
set Name=%~1
set AnyName=
:: MiniMax http://www.dostips.com/forum/viewtopic.php?p=44278#p44278
for %%X in (%PATHEXT%) do @for %%F in (%Name%%%X) do (
@if exist %%~dp$PATH:F\%%F (
Set AnyName=%%~dp$PATH:F%%F
Set LongName=%%~dp$PATH:F%%F in the search path
)
)
SET NAMEEXT=!PATHEXT:.=%1.!
:: Aacini http://www.dostips.com/forum/viewtopic.php?p=44266#p44266
FOR %%N IN (%NameEXT%) DO IF EXIST %%N (
Set AnyName=%CD%\%%N
Set LongName=%CD%\%%N in the current directory
)
If Defined AnyName (
Exit /B 0
) Else (
Exit /B 1
)
Update PathFinder code follows unedited narrative below:
My disorganization in using program folders as current directories and in the path has aggravated me when poor batch script name choices usurp existing ones causing surprising results. Explicit calls cause fewer such problems but make changes a real chore.
I hope that some of the contributors from which I draw much inspiration here might check my code to verify that I have correctly interpreted how the system chooses exactly which file will run from a call statement.
So I offer the following code that I use to see if a command name is free or already in use and perhaps hiding other commands behind it in the search order.
Code: Select all
:PathFinder cmd found Fnx road exts
@goto :ENDofHELP
::PathFinder cmd found Fnx road exts
:: -- Determine if (and from where) a command would run
:: -- cmd [in,opt] - Command name (extension optional)
:: -- Found [out,opt] - 1st fully qualified execution folder
:: -- Fnx [out] - first execution filename
:: -- road [in,opt] - treat as path
:: -- exts [in,opt] - treat as pathext
:: -- console output shows commands blocked by first one
:: -- errorlevel 0 if found or 1 if command not found
::Dependencies: IsItDOS function to check for DOS builtin command
::Acknowledge: Help modelled after JREPL.BAT by Dave Benham, originally posted at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=6044
::
::PathFinder.BAT version 2.2 by John Andrejsons
::
:: Release History:
:: 2015-12-07 v2.2: Added /T to control output
:: 2015-09-15 v2.1: Corrected to reverse PATH and PATHEXT search order
:: 2014-08-30 v2.0: Added HELP and option for output emulationg WHERE command
:: 2015-08-15 v1.2: Added paths loop to really find more than just first one
:: 2015-08-03 v1.1: Added path and pathext options - fixed so rtrim not needed
:: 2015-07-15 v1.0: Post to http://www.dostips.com/forum/viewtopic.php?p=41940
::
::============ Documentation ===========
::
:::
::: Lists path components where a command is found and by what filename.ext
:::
:::PathFinder [ /T ] cmd [found] [Fnx] [road] [exts]
:::
::: [ -H | /? | /?? | /?Version ]
:::
::: /T - Reduces message traffic to appear more like
::: the output of option /T of the 'where' command.
:::
::: cmd - required name of command with or without extension
:::
::: NOTE: * The following four arguments, although optional,
::: are all positional and need a "" placeholder for
::: missing arguments to postion a following selection.
:::
::: found - name of symbolic variable to receive the fully qualified
::: name of the command that would be executed.
:::
::: Fnx - name of symbolic variable to receive name of command
::: including extension that would be executed.
:::
::: road - string in the format of the PATH variable
::: to be used as a hypothetical search path.
:::
::: exts - string in the format of the PATHEXT variable
::: to be used as an override during the search.
:::
::: This command performs a search of the path using PATHEXT order
::: and offers limited function similar to the DOS builtin command 'WHERE'
::: but works in the Windows XP environment which has no such command.
:::
::: In addition a check is made for DOS builtin command status
::: based on help output format criteria in response to the /? parameter.
:::
::: If a symbolic variable 'Mute' is set to the value Rem. (Set "Mute=Rem."),
::: the output is customized to appear like that of the 'WHERE' builtin command
::: This can be activated by /T as the first argument which
::: also shifts the remaining arguments to their expectd places.
:::
::: HELP is available by supplying a single argument:
:::
::: [ /? | -H ] - Writes formal help documentation to stdout.
:::
::: /?? - Same as /? except uses MORE for pagination.
::: This includes all '::' commentary.
:::
::: /?VERSION - Writes the PathFinder version number to stdout.
:::
::: Return Codes:
:::
::: 0 = At least one instance of the specified command was found
:::
::: 1 = Command not found
::: or HELP was requested
:::
::: PathFinder.BAT was written by John Andrejsons, and originally posted at
::: http://www.dostips.com/forum/viewtopic.php?p=41940
:::
============= :ENDofHELP portion ===========
============= :Batch portion follows =======
@Echo Off &SetLOCAL EnableDelayedExpansion &Rem.Keep environment vars uncluttered.
If "%~1"=="" (
:False rem.Return False by setting %errorlevel% to 1.
Set=2>nul
Echo.&Echo.[rc=!ErrorLevel!] from checking passed variables to '%~nx0'
Echo.HELP is available using any of these parameters: -H, /?, /??.
Echo.Error^^! Required command name not supplied. Terminating [rc=1] . . .
Exit /B 1
)
if "%~1" equ "/?" (
For /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A
Exit /b 1
) Else if /I "%~1" equ "-H" 2>nul (
For /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A
Exit /b 1
) Else if /i "%~1" equ "/?Syntax" (
For /f "tokens=* delims=:" %%A in ('findstr "^:::Syntax" "%~f0"') do @echo(%%A
Exit /b 1
) Else if /i "%~1" equ "/?version" (Echo.
For /f "tokens=* delims=:" %%A in ('findstr "^::PathFinder\.BAT" "%~f0"') do @echo(%%A
Exit /b 1
) Else if "%~1" equ "/??" 2>nul (
(For /f "tokens=* delims=:" %%A in ('findstr "^::" "%~f0"') do @echo(%%A)|more /e
Exit /b 1
) Else if /I "%~1" equ "/T" (
Set "mute=Rem."
Shift /1
)
IF Exist "%~nx1" (%Mute%Echo. &%Mute%Echo.Filename "%~1" found ASIS in Current Directory %cd%
%Mute%Echo.and takes precedence before any search path folders.
Set "Found=%cd%\%~1"&Set "Fnx=%~1"
)
Set "tmpd=%TEMP%\'0'"
If Not Exist "%tmpd%" MkDir "%tmpd%"
1>"%tmpd%\PthList.bat" Echo. @Echo OfF
Set "RoadPth=%path%"
If "%~4"=="" (
%Mute%Echo.&%Mute%Echo.Optional path alternative not specified . . .
) Else (%Mute%Echo.
>>"%tmpd%\PthList.bat" Echo. If Exist "%tmpd%\PthList.txt" Erase "%tmpd%\PthList.txt"
>>"%tmpd%\PthList.bat" Echo. Set "roadPth=%%%~4%%"
>>"%tmpd%\PthList.bat" Echo. %Mute%Echo.Optional PATH=%%%~4%%
)
Call "%tmpd%\PthList.bat"
1>"%tmpd%\ExtList.bat" Echo. @Echo OfF
Set Roadext=%pathext%
If "%~5"=="" (
%Mute%Echo.&%Mute%Echo.Optional pathext alternative not specified . . .
) Else (%Mute%Echo.
>>"%tmpd%\ExtList.bat" Echo. If Exist "%tmpd%\ExtList.txt" Erase "%tmpd%\ExtList.txt"
>>"%tmpd%\ExtList.bat" Echo. Set "roadext=%%%~5%%"
>>"%tmpd%\ExtList.bat" Echo. %Mute%Echo.Optional PATHEXT=%%%~5%%
)
Call "%tmpd%\ExtList.bat"
SET Extensions=^>"%tmpd%\ExtsList.txt" Echo.!RoadExt:;=^&^>^>"%tmpd%\ExtsList.txt" Echo.!
%Extensions%
Call:QualFetch "%~1"
If Defined Found GoTo Found &Rem.Bypass rolling through PATH
SET Paths=^>"%tmpd%\PathList.txt" Echo.%~1 !path:;=^&^>^>"%tmpd%\PathList.txt" Echo.%~1 !
%Paths%
%Mute%Echo.&%Mute%Echo.Searching current directory for command "%~n1" . . .
For /F "UseBackQ Tokens=1* delims=" %%A in ("%tmpd%\ExtsList.txt") Do (
If Exist "%~1%%A" (Set "FetchFile=%~1%%A"
FOR /F "UseBackQ tokens=1-4,5* " %%a in (`DIR "%~1%%A" /A:-S-d /-C`) do (
IF /I "%~1%%A"=="%%e" (
If Defined Mute Echo.%%d %%a %%b %%c %CD%\%~1%%A
%Mute%Set <nul /P =Found={
%Mute%Set <nul /P =%CD%\%~1%%A
%Mute%Set <nul /P =}
)
)
%Mute%Echo.&%Mute%Echo.File "!FetchFile!" found in Current Directory "%cd%"
If Not Defined found (
%Mute%Echo.and takes precedence before any search path folders.
Set "Found=%cd%\!FetchFile!" & Set "Fnx=!FetchFile!"
)
)
)
%Mute%Echo.&%Mute%Echo.Searching for command "%~n1" in path folders . . .
For /F "UseBackQ Tokens=1* delims=" %%I in ("%tmpd%\PathList.txt") do (
Set "FetchFile=%%I"
Set "FetchPath=%%J \"
Set "FetchPath=!FetchPath:\ \=!"
Set "FetchPath=!FetchPath: \=!"
Call:QualFetch !FetchFile! !FetchPath!
)
:Found
If Defined Found Echo.
Call IsItDOS %~n1 -q
(EndLOCAL &Rem.Return Values
Set found=%Found%
If "%~2" NEQ "" (SET %~2=%Found%) ELSE (
If Defined Found (
%Mute%Echo.&%Mute%Echo.First in call sequence: '%Found%'
)
)
If "%~3" NEQ "" (SET %~3=%Fnx%)
If Defined Found (
Set "Found="
%Mute%Echo.&Exit /B 0
) Else (
Echo.&Echo.'%~1' was not found in a call path sequence folder.
%mute%Echo.&Exit /B 1
)
)
:QualFetch
For /F "UseBackQ Tokens=1* delims=" %%I in ("%tmpd%\ExtsList.txt") do (
If Exist "%~2\%~1%%I" (
%Mute%Set <nul /P =Found={
FOR /F "UseBackQ tokens=1-4,5* " %%a in (`DIR "%~2\%~1%%I" /A:-S-d /-C`) do (
IF /I "%~1%%I"=="%%e" (
If Defined Mute Set <nul /P =%%d %%a %%b %%c %~2\%~1%%I
If Defined Mute Echo.
%Mute%Set <nul /P =%~2\%~1%%I
)
)
%Mute%Set <nul /P =}
%Mute%Echo.
If Not Defined found (Set "Found=%~2\%~1%%I" & Set "Fnx=%~1%%I")
)
)
Exit /B
The following could be useful in trying it out.
Code: Select all
@Echo Off
If "%~1"=="" Echo.&Echo.Command name is required. Terminating (rc=1) . . .&Exit /B 1
Call PathFinder "%~1" findpath findfile
If %errorlevel%==0 (
Echo.Resulting variables are:
Set Find
) Else (
Echo.[rc=%errorlevel%] No results for "%~1" search.
)
Echo.&Echo.Or with no saving of names:
Call PathFinder "%~1"
Exit /B
My XP system is inoperable for a while so I have only tested it on Windows 7.
[Edited: system working and code tested on XP.]
I welcome critiques or corrections (particularly in method).
John A.