J'utilise souvent des coquilles de rechange (principalement TCC/LE de jpsoft.com) et sous-couches. J'ai trouvé que ce code fonctionne pour une plus large, cas plus général (et il ne nécessite pas 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)
Dans un premier temps, je l'avais utilisé if /i "%~f2"=="%~f3"
dans le sous-programme _is_similar_command
. La modification à if /i "%~$PATH:2"=="%~$PATH:3"
et la vérification de code supplémentaire pour les extensions NULL permet au code de fonctionner pour les shells/sous-shell ouverts avec des chemins non qualifiés (par exemple, sous-shell appelés avec juste 'cmd.exe' ou 'tcc').
Pour les arguments sans extension, ce code n'analyse pas et n'utilise pas les extensions de% PATHEXT%. Il ignore essentiellement la hiérarchie des extensions que CMD.exe utilise lors de la recherche d'une commande sans extension (d'abord tenter FOO.com, puis FOO.exe, puis FOO.bat, etc.). Ainsi, _is_similar_command
vérifie la similarité, et non l'équivalence, entre les deux arguments en tant que commandes shell. Cela pourrait être une source de confusion/erreur, mais ne se poserait probablement jamais comme un problème dans la pratique pour cette application.
Édition: Le code initial était une ancienne version.Le code est maintenant mis à jour à la version la plus récente qui a: (1) un échange %COMSPEC%
et %cmdcmdline%
dans l'appel initial, (2) a ajouté une vérification pour plusieurs arguments %cmdcmdline%
, (3) les messages écho sont plus spécifiques sur ce qui est détecté, et (4) une nouvelle variable %_PAUSE_NEEDED%
a été ajoutée.
Il est à noter que %_FROM_CONSOLE%
est défini en fonction de l'exécution du fichier de commandes directement depuis la ligne de commande de la console ou indirectement via l'explorateur ou d'autres moyens. Ces "autres moyens" peuvent inclure un appel système perl() ou en exécutant une commande telle que cmd /c COMMAND
.
La variable %_PAUSE_NEEDED%
a été ajoutée afin que les processus (tels que perl) qui exécutent le fichier de commandes indirectement puissent ignorer les pauses dans le fichier de commandes. Cela serait important dans les cas où la sortie n'est pas transmise à la console visible (par exemple, perl -e "$o = qx{COMMAND}"
). Si une pause se produit dans un tel cas, le message "Appuyez sur n'importe quelle touche pour continuer.". L'invite de pause ne s'affichera jamais pour l'utilisateur et le processus se bloquera en attente d'une entrée utilisateur non sollicitée. Dans les cas où l'interaction de l'utilisateur est impossible ou interdite, la variable %_PAUSE_NEEDED%
peut être préréglée sur "0" ou "1" (false ou true, respectivement). %_FROM_CONSOLE%
est toujours défini correctement par le code, mais la valeur de %_PAUSE_NEEDED%
n'est pas définie par la suite en fonction de %_FROM_CONSOLE%
. C'est juste passé.
Et notez également que le code détectera incorrectement l'exécution comme indirecte (%_FROM_CONSOLE%
= 0) dans un sous-shell si ce sous-shell est ouvert avec une commande contenant des commutateurs/options (par exemple, cmd /x
). Généralement ce n'est pas un gros problème car les sous-cases sont généralement ouvertes sans commutateurs supplémentaires et %_PAUSE_NEEDED%
peut être réglé sur 0, si nécessaire.
Codeur de caveat.
Pouvez-vous expliquer comment cela fonctionne? –