私は代替シェル (主に 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"
と追加のコード チェックにより、完全修飾されていないパス (たとえば、'cmd.exe' または 'tcc' だけで呼び出されるサブシェル) で開かれたシェル/サブシェルに対してコードが機能するようになります。
拡張子のない引数の場合、このコードは解析せず、%PATHEXT% からの拡張子を使用します。基本的に、拡張子のないコマンドを検索するときに CMD.exe が使用する拡張子の階層を無視します (最初に FOO.com、次に FOO.exe、次に FOO.bat を試行します)。その_is_similar_command
ため、シェル コマンドとしての 2 つの引数の同等性ではなく、類似性をチェックします。これは混乱/エラーの原因になる可能性がありますが、このアプリケーションの実際の問題として発生することはほとんどありません。
編集:最初のコードは古いバージョンでした。コードは最新バージョンに更新されました。(1) スワップ%COMSPEC%
さ%cmdcmdline%
れ、最初の呼び出しで、(2) 複数の%cmdcmdline%
引数のチェックが追加されました。(3) エコーされたメッセージは、検出されたものについてより具体的です。(4) ) 新しい変数%_PAUSE_NEEDED%
が追加されました。
%_FROM_CONSOLE%
は、バッチ ファイルがコンソール コマンド ラインから直接実行されたか、エクスプローラまたはその他の手段を介して間接的に実行されたかに基づいて設定されることに注意してください。これらの「その他の手段」には、perl system() 呼び出し、または などのコマンドの実行が含まれcmd /c COMMAND
ます。
この変数%_PAUSE_NEEDED%
は、バッチ ファイルを間接的に実行するプロセス (perl など) がバッチ ファイル内の一時停止をバイパスできるようにするために追加されました。これは、出力が表示されているコンソールにパイプされていない場合 (例: perl -e "$o = qx{COMMAND}"
) に重要です。このような場合に一時停止が発生すると、「Press any key to continue . . .」というメッセージが表示されます。一時停止プロンプトがユーザーに表示されることはなく、プロセスはユーザー入力のプロンプトが表示されないのを待ってハングします。ユーザーの操作が不可能または許可されていない場合は、%_PAUSE_NEEDED%
変数を "0" または "1" (それぞれ false または true) に事前設定できます。%_FROM_CONSOLE%
は引き続きコードによって正しく設定されますが、 の値%_PAUSE_NEEDED%
はその後 に基づいて設定されません%_FROM_CONSOLE%
。通過するだけです。
%_FROM_CONSOLE%
また、サブシェルがスイッチ/オプション (例: ) を含むコマンドで開かれている場合、コードはサブシェル内での実行を間接的 ( =0) として誤って検出することにも注意してくださいcmd /x
。通常、サブシェルは追加のスイッチなしで開かれ%_PAUSE_NEEDED%
、必要に応じて 0 に設定できるため、これは大きな問題ではありません。
警告コード。