michaeluskov
michaeluskov

Reputation: 1828

Check if command is internal in CMD

I have a command's name and I need to check if this command is internal. How can I do it in a batch script?

Upvotes: 5

Views: 2893

Answers (3)

Lumi
Lumi

Reputation: 15264

Doesn't answer the question, but I made a list of the built-ins (extracted them from the output of HELP.EXE IIRC) and grouped them thematically (which others might find useful or not):

FOR       REM       MD        CLS       START
IF        ECHO      RD        COLOR
GOTO      PAUSE     REN       TITLE     DATE
CALL                MOVE      PATH      TIME
EXIT      VOL       DEL       PROMPT    VER
SET       DIR       COPY
SETLOCAL  CD        MKLINK    ASSOC     VERIFY
ENDLOCAL  PUSHD     TYPE      FTYPE     BREAK
SHIFT     POPD

There are only 38 command plus 5 aliases:

 CD=CHDIR, MD=MKDIR, RD=RMDIR, DEL=ERASE, REN=RENAME

This static list of 43 strings could be used to check if the command is built-in (even though that is not what the OP had in mind).

Upvotes: 0

kichik
kichik

Reputation: 34704

So after a lot of tweaking, and thanks to the help of @Andriy M, it finally works.

@ECHO off

CALL :isInternalCommand dir dirInternal
ECHO is dir internal: %dirInternal%

CALL :isInternalCommand find findInternal
ECHO is find internal: %findInternal%

exit /b 0

:isInternalCommand
SETLOCAL

MKDIR %TEMP%\EMPTY_DIR_FOR_TEST > NUL 2>& 1
CD /D %TEMP%\EMPTY_DIR_FOR_TEST
SET PATH=
%~1 /? > NUL 2>&1
IF ERRORLEVEL 9009 (ENDLOCAL
SET "%~2=no"
) ELSE (ENDLOCAL
SET "%~2=yes"
)

GOTO :EOF

OLD SOLUTION

You can use where. If it fails, the command is probably internal. If it succeeds, you get the executable path that proves it's not internal.

C:\Users\user>where path
INFO: Could not find files for the given pattern(s).

C:\Users\user>where find
C:\Windows\System32\find.exe

EDIT: As the comments suggest, this might not be the best solution if you're looking for portability and not just research. So here's another possible solution.

Set %PATH% to nothing so HELP can't find anything and then run HELP on the command you're trying to check.

C:\Users\user>set PATH=

C:\Users\user>path
PATH=(null)

C:\Users\user>%WINDIR%\System32\help del
Deletes one or more files.

DEL [/P] [/F] [/S] [/Q] [/A[[:]attributes]] names
[...]

C:\Users\user>%WINDIR%\System32\help find
'find' is not recognized as an internal or external command,
operable program or batch file.

This might still fail if the command doesn't have help.

EDIT 2: Never mind, this won't work either. Both cases return %ERRORLEVEL%=1.

Upvotes: 8

dbenham
dbenham

Reputation: 130809

kichik has a good answer. However, it can give a false positive if there happens to be an executable or batch script within the current directory that matches the supplied command name.

The only way I can think of to avoid that problem is to create a folder that is known to be empty within the %TEMP% directory, and then run the test from that folder.

Here is a modified version of kichik's solution that should work.

@echo off
setlocal

::Print the result to the screen
call :isInternal find
call :isInternal dir

::Save the result to a variable
call :isInternal find resultFind
call :isInternal dir  resultDir
set result

exit /b

:isInternal  command  [rtnVar]
setlocal
set "empty=%temp%\empty%random%"
md "%empty%"
pushd "%empty%"
set path=
>nul 2>nul %1 /?
if errorlevel 9009 (set rtn=not internal) else (set rtn=internal)
popd
rd "%empty%"
(
  endlocal
  if "%~2" neq "" (set %~2=%rtn%) else echo %1 is %rtn%
)
exit /b 0

Here is a script that will simply list all internal commands, assuming that HELP includes a complete list of internal commands.

Update: Both FOR and IF have special parsing rules that prevent those commands from working if executed via a FOR variable or delayed expansion. I had to rewrite this script to use a CALL and execute the command via a CALL argument instead.

@echo off
setlocal enableDelayedExpansion
set "empty=%temp%\empty%random%"
md "%empty%"
pushd "%empty%"
for /f "delims= " %%A in ('help^|findstr /rc:"^[^ ][^ ]*  "') do call :test %%A
popd
rd "%empty%"
exit /b

:test
setlocal
set path=
%1 /? >nul 2>nul
if not errorlevel 9009 echo %1
exit /b 0

Upvotes: 3

Related Questions