Я часто использую альтернативные оболочки (в первую очередь TCC / LE от jpsoft.com) и подоболочки. Я обнаружил, что этот код работает для более широкого, более общего случая (и не требует 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
. Изменение на if /i "%~$PATH:2"=="%~$PATH:3"
и дополнительная проверка кода для расширений NULL позволяют коду работать для оболочек / подоболочек, открытых с неполными путями (например, подоболочки, вызываемые просто «cmd.exe» или «tcc»).
Для аргументов без расширений этот код не анализирует и не использует расширения из% PATHEXT%. По сути, он игнорирует иерархию расширений, которую CMD.exe использует при поиске команды без расширения (сначала попытка FOO.com, затем FOO.exe, затем FOO.bat и т. Д.). Таким образом, _is_similar_command
проверяет сходство, а не эквивалентность, между двумя аргументами в качестве команд оболочки. Это может быть источником путаницы / ошибки, но, по всей вероятности, никогда не возникнет как проблема на практике для этого приложения.
Редактировать: Первоначальный код был старой версией. Теперь код обновлен до самой последней версии, которая имеет: (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» (соответственно, false или true). %_FROM_CONSOLE%
по-прежнему корректно устанавливается кодом, но значение %_PAUSE_NEEDED%
впоследствии не устанавливается на основе %_FROM_CONSOLE%
. Это просто прошло.
И также обратите внимание, что код будет неправильно определять выполнение как косвенное (%_FROM_CONSOLE%
= 0) в подоболочке, если этот подоболочек открывается командой, содержащей переключатели / опции (например, cmd /x
). Как правило, это не большая проблема, поскольку подоболочки обычно открываются без дополнительных переключателей, и %_PAUSE_NEEDED%
может быть установлен на 0, когда это необходимо.
Предостережение Codor.