Reputation: 199
I have tried to make a script that works like which
. So I want to check if this command is internal or external or both. I tried to execute program, but when the program(.exe for example) was incorrect my program exit with errors so I tried to call help
for this program. But now if I try to check for example echo
and I have echo.exe
in my current dir I get that it is external command, but not internal. So my question is how to do it right. How to check if this program internal or external. Thanks.
Here is my code:
@echo off
setlocal enabledelayedexpansion
if "%1"=="" goto help
:start
if not "%1"=="" (
shift
if "%1"=="/?" goto help
goto :start
)
set arg=%*
for %%a in ("%pathext:;=" "%") do (
echo %arg%|findstr /E /I %%a >nul
rem If file was given with extension
if not ERRORLEVEL 1 goto with_rashr
)
set ext=0
for %%a in ("%pathext:;=" "%") do (
if EXIST "%CD%\!arg!%%~a" (
echo This is an external command: %CD%\!arg!%%~a
set ext=1
goto :internal
)
)
for %%G in ("%path:;=" "%") do (
for %%a in ("%pathext:;=" "%") do (
if EXIST "%%~G\!arg!%%~a" (
echo This is an external command: %%~G\!arg!%%~a
set ext=1
goto :internal
)
)
)
goto :internal
:with_rashr
echo Command with extension was given
if EXIST "%CD%\!arg!" (
echo This is an external command: %CD%\!arg!
set ext=1
goto :internal
)
for %%G in ("%path:;=" "%") do (
if EXIST "%%~G\!arg!" (
echo This is an external command: %%~G\!arg!
set ext=1
goto :internal
)
)
:internal
set PATH=
rem set PATH=%PATH%;%CD%
help %arg% >nul 2>&1
rem set error_check=%ERRORLEVEL%
rem echo %error_check%
rem %arg% /?
rem ERRORLEVEL 9009 when a batch attempts to execute a program that is not found.
rem echo %ext%
if ERRORLEVEL 9009 (
echo We couldn't execute command
if "%ext%"=="0" (
echo This is not a command
)
endlocal
goto :EOF
)
if "%ext%"=="1" (
if ERRORLEVEL 0 (
echo This is also an internal command
)
endlocal
goto :EOF
)
echo This is internal command
endlocal
goto :EOF
:help
echo Like which
echo Shows if this command external or internal
Upvotes: 5
Views: 1779
Reputation: 130809
Good question, and it is surprisingly difficult to solve.
I thought I had a good working version at http://ss64.org/viewtopic.php?pid=5752#p5752, in which I responded to another persons attempt to do basically the same thing. But after reading your question, I realize my old "solution" suffers from the same problem - it falsely reports an internal command as an external command if there happens to be an exe with the same root name somewhere in the path.
I was first checking if I could find an external command, and if not, then I assumed any command that HELP knew about was an internal command.
I think I now have a working version.
I check to see if the command is internal first, using similar techniques as you tried. Some twists that I added.
(CALL )
command is a quick method to clear the ERRORLEVELAs far as I know, every internal command will print out help info if given an argument of /?
. If the command is not internal, then it will fail to execute and set ERRORLEVEL to 9009 because PATH is empty and the current directory is empty.
::WHICH CommandName [ReturnVar]
::
:: Determines the full path of the file that would execute if
:: CommandName were executed.
::
:: The result is stored in variable ReturnVar, or else it is
:: echoed to stdout if ReturnVar is not specified.
::
:: If no file is found, then an error message is echoed to stderr.
::
:: The ERRORLEVEL is set to one of the following values
:: 0 - Success: A matching file was found
:: 1 - CommandName is an internal command
:: 2 - No file was found and CommandName is not an internal command
:: 3 - Improper syntax - no CommandName specified
::
@echo off
setlocal disableDelayedExpansion
set "file=%~1"
setlocal enableDelayedExpansion
if not defined file (
>&2 echo Syntax error: No CommandName specified
exit /b 3
)
:: test for internal command
echo(!file!|findstr /i "[^abcdefghijklmnopqrstuvwxyz]" >nul || (
set "empty=!temp!\emptyFolder"
md "!empty!" 2>nul
del /q "!empty!\*" 2>nul >nul
setlocal
pushd "!empty!"
set path=
(call )
!file! /? >nul 2>nul
if not errorlevel 9009 (
>&2 echo "!file!" is an internal command
popd
exit /b 1
)
popd
endlocal
)
:: test for external command
set "noExt="
if "%~x1" neq "" if "!PATHEXT:%~x1=!" neq "!PATHEXT!" set noExt="";
set "modpath=.\;!PATH!"
@for %%E in (%noExt%%PATHEXT%) do @for %%F in ("!file!%%~E") do (
setlocal disableDelayedExpansion
if not "%%~$modpath:F"=="" if not exist "%%~$modpath:F\" (
endlocal & endlocal & endlocal
if "%~2"=="" (echo %%~$modpath:F) else set "%~2=%%~$modpath:F"
exit /b 0
)
endlocal
)
endlocal
>&2 echo "%~1" is not a valid command
exit /b 2
Upvotes: 7