¿Hay alguna forma en un script por lotes de mantener la consola abierta solo si se invoca desde el Administrador de Windows?

StackOverflow https://stackoverflow.com/questions/510156

Pregunta

Tengo un script por lotes de DOS que invoca una aplicación Java que interactúa con el usuario a través de la interfaz de usuario de la consola.Por el bien del argumento, llamémoslo runapp.bat y su contenido sea

java com.example.myApp

Si el script por lotes se invoca en una consola, todo funciona bien.Sin embargo, si el script se invoca desde el Administrador de ventanas, la consola recién abierta se cierra tan pronto como la aplicación termina de ejecutarse.Lo que quiero es que la consola quede abierta en todos los casos.

Conozco los siguientes trucos:

  • Agrega un pause comando al final del script.Esto es un poco feo por si acaso. runapp.bat se invoca desde la línea de comando.

  • crear un nuevo shell usando cmd /K java com.example.myApp Esta es la mejor solución que encontré hasta ahora, pero deja un entorno de shell adicional cuando se invoca desde la línea de comando, por lo que llamar exit en realidad no cierra el caparazón.

¿Existe una mejor manera?

¿Fue útil?

Solución

Vea esta pregunta: La detección de cómo se ejecuta un archivo por lotes

Este script no se detendrá si se ejecuta desde la consola de comandos, pero si hizo doble clic en el Explorador:

@echo off
setlocal enableextensions

set SCRIPT=%0
set DQUOTE="

:: Detect how script was launched
@echo %SCRIPT:~0,1% | findstr /l %DQUOTE% > NUL
if %ERRORLEVEL% EQU 0 set PAUSE_ON_CLOSE=1

:: Run your app
java com.example.myApp

:EXIT
if defined PAUSE_ON_CLOSE pause

Otros consejos

Yo prefiero usar %cmdcmdline% tal como fue anunciado en el comentario a la respuesta de Patrick a la otra pregunta (que no he encontrado aunque mirado). De esa manera, incluso si alguien decide usar comillas para llamar a la secuencia de comandos por lotes, no va a disparar el falso positivo.

Mi solución final:

@echo off
java com.example.myApp %1 %2

REM "%SystemRoot%\system32.cmd.exe"   when from console
REM cmd /c ""[d:\path\script.bat]" "  when from windows explorer

@echo %cmdcmdline% | findstr /l "\"\"" >NUL
if %ERRORLEVEL% EQU 0 pause
cmd /K java com.example.myApp & pause & exit

hará el trabajo. El y ejecutará el comando, uno tras otro. Si utiliza && se puede romper si uno falla.

Incluir esta línea en un archivo por lotes y haga doble clic en el archivo por lotes en el explorador:

cmd / k "secuencias de comandos dentro de estas citas separadas por &&"

Por ejemplo

cmd / k "cd ../ .. && && cd dir some_directory"

El complemento completo de opciones para cmd se puede encontrar aquí

Con frecuencia uso shells y subshells alternativos (principalmente TCC/LE de jpsoft.com).Descubrí que este código funciona para un caso más amplio y general (y no requiere 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 )

Inicialmente había usado if /i "%~f2"=="%~f3" en el _is_similar_command subrutina.el cambio a if /i "%~$PATH:2"=="%~$PATH:3" y la verificación de código adicional para extensiones NULL permite que el código funcione para shells/subshells abiertos con rutas no completamente calificadas (por ejemplo, subshells llamados solo con 'cmd.exe' o 'tcc').

Para argumentos sin extensiones, este código no analiza ni utiliza las extensiones de %PATHEXT%.Básicamente, ignora la jerarquía de extensiones que utiliza CMD.exe cuando busca un comando sin extensión (primero intenta FOO.com, luego FOO.exe, luego FOO.bat, etc.).Entonces, _is_similar_command comprueba la similitud, no la equivalencia, entre los dos argumentos como comandos de shell.Esto podría ser una fuente de confusión/error, pero, con toda probabilidad, nunca surgirá como un problema en la práctica para esta aplicación.

Editar: El código inicial era una versión antigua.El código ahora está actualizado a la versión más reciente que tiene:(1) un intercambiado %COMSPEC% y %cmdcmdline% en la llamada inicial, (2) agregó un cheque por múltiples %cmdcmdline% argumentos, (3) los mensajes repetidos son más específicos sobre lo que se detecta, y (4) una nueva variable %_PAUSE_NEEDED% fue añadido.

se debe notar que %_FROM_CONSOLE% se establece en función específicamente de si el archivo por lotes se ejecutó directamente desde la línea de comandos de la consola o indirectamente a través del explorador o algún otro medio.Estos "otros medios" pueden incluir una llamada al sistema Perl() o ejecutando un comando como cmd /c COMMAND.

La variable %_PAUSE_NEEDED% Se agregó para que los procesos (como Perl) que ejecutan el archivo por lotes indirectamente puedan evitar las pausas dentro del archivo por lotes.Esto sería importante en los casos en los que la salida no se canaliza a la consola visible (p. ej., perl -e "$o = qx{COMMAND}").Si se produce una pausa en tal caso, aparecerá el mensaje "Presione cualquier tecla para continuar"..." El mensaje de pausa nunca se mostrará al usuario y el proceso se bloqueará esperando una entrada no solicitada del usuario.En los casos en los que la interacción del usuario no sea posible o no esté permitida, el %_PAUSE_NEEDED% La variable se puede preestablecer en "0" o "1" (falso o verdadero respectivamente). %_FROM_CONSOLE% todavía está configurado correctamente por el código, pero el valor de %_PAUSE_NEEDED% no se establece posteriormente basándose en %_FROM_CONSOLE%.Acaba de pasar.

Y también tenga en cuenta que el código detectará incorrectamente la ejecución como indirecta (%_FROM_CONSOLE%=0) dentro de un subshell si ese subshell se abre con un comando que contiene modificadores/opciones (por ejemplo, cmd /x).Generalmente esto no es un gran problema ya que los subshells generalmente se abren sin interruptores adicionales y %_PAUSE_NEEDED% se puede establecer en 0, cuando sea necesario.

Advertencia codor.

@echo% CMDCMDLINE% | buscar / i "/ c"> nul && pausa

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top