批处理脚本中是否有一种方法可以使控制台仅在从 Windows 管理器调用时保持打开状态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/510156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a way in a batch script to keep the console open only if invoked from Windows Manager?
提问by ykaganovich
I have a DOS batch script that invokes a java application which interacts with the user through the console UI. For the sake of argument, let's call it runapp.bat
and its contents be
我有一个 DOS 批处理脚本,它调用一个 Java 应用程序,该应用程序通过控制台 UI 与用户交互。为了论证起见,我们称之为它runapp.bat
,它的内容是
java com.example.myApp
If the batch script is invoked in a console, everything works fine. However, if the script is invoked from the Window Manager, the newly opened console closes as soon as the application finishes executing. What I want is for the console to stay open in all cases.
如果在控制台中调用批处理脚本,则一切正常。但是,如果脚本是从窗口管理器调用的,新打开的控制台会在应用程序执行完毕后立即关闭。我想要的是控制台在所有情况下都保持打开状态。
I know of the following tricks:
我知道以下技巧:
add a
pause
command at the end of the script. This is a bit ugly in caserunapp.bat
is invoked from the command line.create a new shell using
cmd /K java com.example.myApp
This is the best solution I found so far, but leaves an extra shell environment when invoked from the command line, so that callingexit
doesn't actually close the shell.
pause
在脚本的末尾添加一个命令。如果runapp.bat
从命令行调用,这有点难看。创建一个新的 shell 使用
cmd /K java com.example.myApp
这是迄今为止我找到的最好的解决方案,但是从命令行调用时会留下一个额外的 shell 环境,因此调用exit
实际上并没有关闭 shell。
Is there a better way?
有没有更好的办法?
回答by Patrick Cuff
See this question: Detecting how a batch file was executed
看到这个问题:检测批处理文件是如何执行的
This script will not pause if run from the command console, but will if double-clicked in Explorer:
如果从命令控制台运行,此脚本不会暂停,但如果在资源管理器中双击,则会暂停:
@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
回答by ykaganovich
I prefer using %cmdcmdline%
as posted in the comment to Patrick's answer to the other question (which I didn't find although looked). That way, even if someone decides to use quotes to call the batch script, it won't trigger the false positive.
我更喜欢使用%cmdcmdline%
帕特里克对另一个问题的回答(虽然看起来我没有找到)的评论中发布的那样。这样,即使有人决定使用引号来调用批处理脚本,也不会触发误报。
My final solution:
我的最终解决方案:
@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
回答by Totonga
cmd /K java com.example.myApp & pause & exit
will do the job. The & will execute the command one after another. If you use && you can break if one fails.
会做的工作。& 将一个接一个地执行命令。如果您使用 && 您可以在失败时中断。
回答by tjb
Include this line in a batch file and double click on the batch file in explorer:
将此行包含在批处理文件中,然后在资源管理器中双击批处理文件:
cmd /k "script commands within these quotes seperated by &&"
cmd /k "这些引号内的脚本命令由 && 分隔"
For example
例如
cmd /k "cd ../.. && dir && cd some_directory"
cmd /k "cd ../.. && dir && cd some_directory"
The full complement of options to cmd can be found here
可以在此处找到 cmd 选项的完整补充
回答by rivy
I frequently use alternate shells (primarily TCC/LE from jpsoft.com) and subshells. I've found that this code works for a wider, more general case (and it doesn't require FINDSTR):
我经常使用备用 shell(主要来自 jpsoft.com 的 TCC/LE)和子 shell。我发现此代码适用于更广泛、更一般的情况(并且不需要 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 )
Initially, I had used if /i "%~f2"=="%~f3"
in the _is_similar_command
subroutine. The change to if /i "%~$PATH:2"=="%~$PATH:3"
and the additional code checking for NULL extensions allows the code to work for shells/subshells opened with non-fully qualified paths (eg, subshells called with just 'cmd.exe' or 'tcc').
最初,我if /i "%~f2"=="%~f3"
在_is_similar_command
子程序中使用过。if /i "%~$PATH:2"=="%~$PATH:3"
对 NULL 扩展的更改和附加代码检查允许代码适用于使用非完全限定路径打开的外壳程序/子外壳程序(例如,仅使用“cmd.exe”或“tcc”调用的子外壳程序)。
For arguments without extensions, this code does not parse and use the extensions from %PATHEXT%. It essentially ignores the hierarchy of extensions that CMD.exe uses when searching for a command without extension (first attempting FOO.com, then FOO.exe, then FOO.bat, etc.). So, _is_similar_command
checks for similarity, not equivalence, between the two arguments as shell commands. This could be a source of confusion/error, but will, in all likelyhood, never arise as a problem in practice for this application.
对于没有扩展名的参数,此代码不会解析和使用来自 %PATHEXT% 的扩展名。它本质上忽略了 CMD.exe 在搜索没有扩展名的命令时使用的扩展的层次结构(首先尝试 FOO.com,然后是 FOO.exe,然后是 FOO.bat,等等)。因此,_is_similar_command
作为 shell 命令检查两个参数之间的相似性,而不是等效性。这可能是混淆/错误的根源,但很可能在此应用程序的实践中永远不会出现问题。
Edit:Initial code was an old version. The code is now updated to the most recent version which has: (1) a swapped %COMSPEC%
and %cmdcmdline%
in the initial call, (2) added a check for multiple %cmdcmdline%
arguments, (3) echoed messages are more specific about what is detected, and (4) a new variable %_PAUSE_NEEDED%
was added.
编辑:初始代码是旧版本。代码现在更新到最新版本,其中包含:(1)在初始调用中进行了交换%COMSPEC%
和%cmdcmdline%
调用,(2) 添加了对多个%cmdcmdline%
参数的检查,(3) 回显消息更具体地说明了检测到的内容,以及 (4) )%_PAUSE_NEEDED%
添加了一个新变量。
It should be noted that %_FROM_CONSOLE%
is set based specifically on whether the batch file was excecuted directly from the console command line or indirectly through explorer or some other means. These "other means" can include a perl system() call or by executing a command such as cmd /c COMMAND
.
需要注意的%_FROM_CONSOLE%
是,具体是根据批处理文件是直接从控制台命令行执行还是通过资源管理器或其他方式间接执行来设置的。这些“其他方式”可以包括 perl system() 调用或通过执行诸如cmd /c COMMAND
.
The variable %_PAUSE_NEEDED%
was added so that processes (such as perl) which execute the batch file indirectly can bypass pauses within the batch file. This would be important in cases in which output is not piped to the visible console (eg, perl -e "$o = qx{COMMAND}"
). If a pause occurs in such a case, the "Press any key to continue . . ." pause prompt would never be displayed to the user and the process will hang waiting for unprompted user input. In instances where user interaction is either not possible or not allowed, the %_PAUSE_NEEDED%
variable can be preset to "0" or "1" (false or true respectively). %_FROM_CONSOLE%
is still set correctly by the code, but the value of %_PAUSE_NEEDED%
is not subsequently set based upon %_FROM_CONSOLE%
. It is just passed through.
%_PAUSE_NEEDED%
添加了该变量,以便间接执行批处理文件的进程(例如 perl)可以绕过批处理文件中的暂停。在输出未通过管道传送到可见控制台(例如,perl -e "$o = qx{COMMAND}"
)的情况下,这将很重要。如果在这种情况下出现暂停,则“按任意键继续...” 暂停提示永远不会显示给用户,并且进程将挂起等待无提示的用户输入。在用户交互不可能或不允许的情况下,%_PAUSE_NEEDED%
变量可以预设为“0”或“1”(分别为假或真)。%_FROM_CONSOLE%
仍然由代码正确设置,但%_PAUSE_NEEDED%
随后不会基于 设置的值%_FROM_CONSOLE%
。它只是通过。
And also note that the code will incorrectly detect execution as indirect (%_FROM_CONSOLE%
=0) within a subshell if that subshell is opened with a command containing switches/options (eg, cmd /x
). Generally this isn't a big problem as subshells are usually opened without extra switches and %_PAUSE_NEEDED%
can be set to 0, when necessary.
还要注意,%_FROM_CONSOLE%
如果使用包含开关/选项(例如,cmd /x
)的命令打开子外壳,代码将错误地检测到子外壳内的间接执行(=0 )。通常这不是一个大问题,因为子外壳通常在没有额外开关的情况下打开,并且%_PAUSE_NEEDED%
可以在必要时设置为 0。
Caveat codor.
警告气味。
回答by Dave Brown
@echo %CMDCMDLINE% | find /I " /c " >nul && pause
@echo %CMDCMDLINE% | find /I " /c " >nul && pause