在批处理脚本执行“,这”命令 [英] Implement 'which' command in batch script

查看:172
本文介绍了在批处理脚本执行“,这”命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让一个脚本,就像。所以我想,以检查是否该命令的内部或外部或两者兼而有之。我试图执行的程序,但是当程序(.exe举例来说)是不正确的我有错误的程序退出,所以我试着打帮助对这一计划。但现在,如果我尝试检查,例如回声和我有 echo.exe 在我的当前目录,我得到它是外部命令,而不是内部。所以我的问题是怎么做是正确的。如何检查是否该程序内部还是外部。谢谢。
这里是我的code:

 关闭@echo
SETLOCAL enabledelayedexpansion
如果%1==转到帮助:开始
如果不是%1==(
    转移
    如果%1==/?转到帮助
    转到:开始

设置ARG =%*对于一个%%在(%PATHEXT:=,%),做(
    回声%ARG%| FINDSTR / E / I %% A> NUL
    REM如果文件是用特定扩展名
    如果没有ERRORLEVEL 1页转到with_rashr
)集EXT = 0
对于一个%%在(%PATHEXT:=,%),做(
    如果存在%CD%\\!阿根廷!%%〜一(
        回声这是一个外部命令:%​​CD%\\ ARG %%〜一个!
        集EXT = 1
        转到:内部
    )
)在%% G(%路径:=,%),做(
    对于一个%%在(%PATHEXT:=,%),做(
        如果存在%%〜摹\\!阿根廷!%%〜一(
            回声这是一个外部命令:!%%〜摹\\ ARG %%〜一
            集EXT = 1
            转到:内部
        )
    )

转到:内部:with_rashr
扩展名为echo命令给出
如果存在%CD%\\!ARG! (
    回声这是一个外部命令:%​​CD%\\ ARG!
    集EXT = 1
    转到:内部

在%% G(%路径:=,%),做(
    如果存在%%〜摹\\!ARG! (
        回声这是一个外部命令:%%〜摹\\ ARG!
        集EXT = 1
        转到:内部
    )
):内部
设置PATH =
REM SET PATH =%PATH%;%CD%
帮%ARG%GT; NUL 2 - ;&放大器; 1
REM SET error_check =%ERRORLEVEL%
REM回声%error_check%
REM%ARG%/?
REM ERRORLEVEL 9009时,一批试图执行未找到的程序。
REM回声%EXT%
如果ERRORLEVEL 9009(
    回声我们无法执行命令
    如果%EXT%==0(
        回声这不是一个命令
    )
    ENDLOCAL
    GOTO:EOF

如果%EXT%==1(
    如果ERRORLEVEL 0(
        回声这也是一个内部命令
    )
    ENDLOCAL
    GOTO:EOF

回声这是内​​部命令ENDLOCAL
GOTO:EOF:帮帮我
回声喜欢哪
回波显示,如果该命令外部或内部


解决方案

这个问题问得好,这是令人惊讶的难以解决的问题。

我想我在 http://ss64.org/viewtopic有一个很好的工作版本的.php?PID = 5752#p5752 ,在我回答到另一个人尝试这样做基本上是同样的事情。但是看完你的问题后,我意识到我的老解决方案,从同一个问题的困扰 - 它错误地报告内部命令,如果碰巧是用相同的根名称某处路径中的exe文件的外部命令

我第一次检查,如果我能找到一个外部命令,如果没有,那么我认为HELP知道是一个内部命令的任何命令。

我想我现在有一个工作版本。

我检查,看看是否该命令是内部首先,使用类似的技术如你尝试。有些曲折,我补充说。


  • 我取决于%temp%文件夹(我创建它,如果它不存在)的空文件夹

  • 我担心命令注入,让我确认命令包含什么,但我信我做内部测试之前。

  • (CALL)命令是一个快捷的方法来清除ERRORLEVEL

据我所知,所有的内部命令将打印出帮助信息如果给 / 的参数。如果命令不是内部的,那么它会因为PATH是空的,当前目录是空的无法执行,并设置ERRORLEVEL为9009。

  :: WHICH的CommandName [ReturnVar]
::
::确定,将执行,如果该文件的完整路径
:: CommandName的被处决。
::
::的结果存储在变量ReturnVar,否则它是
::呼应如果未指定ReturnVar是到标准输出。
::
::如果没有找到文件,然后一个错误信息回显到标准错误。
::
::的错误级别被设置为以下值中的一个
:: 0 - 成功:匹配的文件被发现
:: 1 - CommandName的是一个内部命令
:: 2 - 没有文件被发现的CommandName不是内部命令
:: 3 - 语法不当 - 没有指定的CommandName
::
关闭@echo
SETLOCAL disableDelayedExpansion设置文件=%〜1
SETLOCAL enableDelayedExpansion如果没有定义文件(
  >和2回声语法错误:没有指定的CommandName
  退出/ B 3

::测试内部命令
!回声(文件| FINDSTR /我[^ ABCDEFGHIJKLMNOPQRSTUVWXYZ]> NUL ||(
  设置空=!温度!\\ emptyFolder
  MD!空! 2 - ; NUL
  德尔/ Q 2 - 空\\ *!; NUL> NUL
  SETLOCAL
  PUSHD!空!
  设置path =
  (通话)
  !文件! /? > NUL 2 - ; NUL
  如果没有ERRORLEVEL 9009(
    >和2回声!文件!是一个内部命令
    POPD
    退出/ B 1
  )
  POPD
  ENDLOCAL

::测试外部命令
设置noExt =
如果%〜X1NEQ如果PATHEXT:%〜X1 =! NEQ!PATHEXT!设置noExt =;
设置MODPATH = \\ ;!道路!
@for %% E的(%noExt %% PATHEXT%)在做@for %% F(!文件!%%〜E)做(
  SETLOCAL disableDelayedExpansion
  如果不是%%〜$ MODPATH:F==如果不存在%%〜$ MODPATH:F \\(
    ENDLOCAL&安培; ENDLOCAL&安培; ENDLOCAL
    如果%〜2==(回声%%〜$ MODPATH:F),否则设置%〜2 = %%〜$ MODPATH:F
    退出/ B 0
  )
  ENDLOCAL

ENDLOCAL
>和2回声%〜1不是一个有效的命令
出口/ B 2

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

解决方案

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.

  • I am depending on an empty folder in the %temp% folder (I create it if it does not exist)
  • I worry about command injection, so I verify that the command contains nothing but letters before I do my internal test.
  • The (CALL ) command is a quick method to clear the ERRORLEVEL

As 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

这篇关于在批处理脚本执行“,这”命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆