我经常使用备用外壳(主要是来自 jpsoft.com 的 TCC/LE)和子外壳。我发现这段代码适用于更广泛、更一般的情况(并且不需要 FINDSTR):
@echo off & setlocal
if "%CMDEXTVERSION%"=="" ( echo REQUIRES command extensions & exit /b 1 ) &:: REQUIRES command extensions for %cmdcmdline% and %~$PATH:1 syntax
call :_is_similar_command _FROM_CONSOLE "%COMSPEC%" %cmdcmdline%
if "%_PAUSE_NEEDED%"=="0" ( goto :_START )
if "%_PAUSE_NEEDED%"=="1" ( goto :_START )
set _PAUSE_NEEDED=0
if %_FROM_CONSOLE% equ 0 ( set _PAUSE_NEEDED=1 )
goto :_START
::
:_is_similar_command VARNAME FILENAME1 FILENAME2
:: NOTE: not _is_SAME_command; that would entail parsing PATHEXT and concatenating each EXT for any argument with a NULL extension
setlocal
set _RETVAL=0
:: more than 3 ARGS implies %cmdcmdline% has multiple parts (therefore, NOT direct console execution)
if NOT [%4]==[] ( goto :_is_similar_command_RETURN )
:: deal with NULL extensions (if both NULL, leave alone; otherwise, use the non-NULL extension for both)
set _EXT_2=%~x2
set _EXT_3=%~x3
if NOT "%_EXT_2%"=="%_EXT_3%" if "%_EXT_2%"=="" (
call :_is_similar_command _RETVAL "%~2%_EXT_3%" "%~3"
goto :_is_similar_command_RETURN
)
if NOT "%_EXT_2%"=="%_EXT_3%" if "%_EXT_3%"=="" (
call :_is_similar_command _RETVAL "%~2" "%~3%_EXT_2%"
goto :_is_similar_command_RETURN
)
::if /i "%~f2"=="%~f3" ( set _RETVAL=1 ) &:: FAILS for shells executed with non-fully qualified paths (eg, subshells called with 'cmd.exe' or 'tcc')
if /i "%~$PATH:2"=="%~$PATH:3" ( set _RETVAL=1 )
:_is_similar_command_RETURN
endlocal & set "%~1=%_RETVAL%"
goto :EOF
::
:_START
if %_FROM_CONSOLE% EQU 1 (
echo EXEC directly from command line
) else (
echo EXEC indirectly [from explorer, dopus, perl system call, cmd /c COMMAND, subshell with switches/ARGS, ...]
)
if %_PAUSE_NEEDED% EQU 1 ( pause )
最初,我if /i "%~f2"=="%~f3"
在_is_similar_command
子程序中使用过。对 NULL 扩展的更改if /i "%~$PATH:2"=="%~$PATH:3"
和附加代码检查允许代码适用于以非完全限定路径打开的 shell/子shell(例如,仅使用“cmd.exe”或“tcc”调用的子shell)。
对于没有扩展名的参数,此代码不会解析和使用来自 %PATHEXT% 的扩展名。它基本上忽略了 CMD.exe 在搜索没有扩展名的命令时使用的扩展名的层次结构(首先尝试 FOO.com,然后是 FOO.exe,然后是 FOO.bat,等等)。因此,_is_similar_command
检查两个参数之间的相似性,而不是等价性作为 shell 命令。这可能是混淆/错误的来源,但很可能在此应用程序的实践中不会出现问题。
编辑:初始代码是旧版本。代码现在更新到最新版本,它具有:(1)交换%COMSPEC%
并%cmdcmdline%
在初始调用中,(2)添加了对多个%cmdcmdline%
参数的检查,(3)回显的消息更具体地说明检测到的内容,以及(4 ) 添加了一个新变量%_PAUSE_NEEDED%
。
需要注意的是,%_FROM_CONSOLE%
具体是根据批处理文件是直接从控制台命令行执行还是通过资源管理器或其他方式间接执行的。这些“其他方式”可以包括 perl system() 调用或通过执行诸如cmd /c COMMAND
.
添加了该变量%_PAUSE_NEEDED%
,以便间接执行批处理文件的进程(例如 perl)可以绕过批处理文件中的暂停。这在输出未通过管道传输到可见控制台(例如,perl -e "$o = qx{COMMAND}"
)的情况下很重要。如果在这种情况下发生暂停,“按任意键继续......” 暂停提示永远不会显示给用户,并且进程将挂起等待未经提示的用户输入。在用户交互不可能或不允许的情况下,该%_PAUSE_NEEDED%
变量可以预设为“0”或“1”(分别为假或真)。%_FROM_CONSOLE%
仍由代码正确设置,但 的值%_PAUSE_NEEDED%
随后并未基于%_FROM_CONSOLE%
. 它只是通过。
还要注意,%_FROM_CONSOLE%
如果使用包含开关/选项(例如,)的命令打开子shell,代码将错误地检测到子shell 内的间接执行(=0 cmd /x
)。通常这不是一个大问题,因为子shell 通常在没有额外开关的情况下打开,并且%_PAUSE_NEEDED%
可以在必要时设置为 0。
警告编码。