Есть ли способ в пакетном скрипте сохранить консоль открытой, только если она вызывается из Windows Manager? - PullRequest
11 голосов
/ 04 февраля 2009

У меня есть пакетный скрипт DOS, который вызывает Java-приложение, которое взаимодействует с пользователем через консольный интерфейс. Для аргумента давайте назовем это runapp.bat, а его содержимое будет

java com.example.myApp

Если пакетный скрипт вызывается в консоли, все работает нормально. Однако, если скрипт вызывается из диспетчера окон, вновь открытая консоль закрывается, как только приложение завершает работу. Я хочу, чтобы консоль оставалась открытой во всех случаях.

Мне известны следующие уловки:

  • добавить команду pause в конце скрипта. Это немного уродливо, если runapp.bat вызывается из командной строки.

  • создать новую оболочку, используя cmd /K java com.example.myApp Это лучшее решение, которое я нашел до сих пор, но оставляет дополнительную среду оболочки при вызове из командной строки, поэтому вызов exit фактически не закрывает оболочку .

Есть ли лучший способ?

Ответы [ 6 ]

12 голосов
/ 04 февраля 2009

См. Этот вопрос: Определение способа выполнения командного файла

Этот сценарий не будет останавливаться при запуске из командной консоли, но будет выполняться при двойном щелчке в проводнике:

@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
3 голосов
/ 10 июня 2009
cmd /K java com.example.myApp & pause & exit

сделает работу. & Выполнит команду один за другим. Если вы используете &&, вы можете сломаться, если не получится.

3 голосов
/ 04 февраля 2009

Я предпочитаю использовать %cmdcmdline%, как указано в комментарии к ответу Патрика на другой вопрос (который я не нашел, хотя посмотрел) Таким образом, даже если кто-то решит использовать кавычки для вызова пакетного сценария, он не вызовет ложное срабатывание.

Мое окончательное решение:

@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
1 голос
/ 04 декабря 2010

Включите эту строку в командный файл и дважды щелкните по командному файлу в проводнике:

Команды сценария

cmd / k "в этих кавычках разделены &&"

Например

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

Полный набор опций для cmd можно найти здесь

0 голосов
/ 18 апреля 2014

@ echo% CMDCMDLINE% | find / I "/ c"> nul && pause

0 голосов
/ 03 мая 2009

Я часто использую альтернативные оболочки (в первую очередь 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.

...