双击时如何使Windows批处理文件暂停?
Posted
技术标签:
【中文标题】双击时如何使Windows批处理文件暂停?【英文标题】:How to make windows batch file pause when double-clicked? 【发布时间】:2009-05-20 08:36:51 【问题描述】:我编写了一个批处理文件来自动执行一些任务。我可以从命令窗口运行它,它会运行并显示结果。如果我从资源管理器中双击它,它会立即运行并终止,所以我看不到结果。
如果我通过双击图标启动批处理文件窗口,是否有办法让批处理文件窗口保持打开状态,直到我关闭它?
当我从命令行调用批处理文件时,我不想传递 /nopause 参数或其他东西。我想要一个解决方案,我可以使用批处理文件而不必做任何特别的事情?
谢谢。
注意我不希望它在从命令行运行时暂停!!我可以从另一个批处理文件中调用这个批处理文件来执行大量操作。在那种情况下,我不能坐在那里继续按 Enter。
理想情况下,我最好将一些代码放入批处理文件中,这样它就可以计算出它是从哪里开始的,然后酌情暂停或不暂停。
【问题讨论】:
【参考方案1】:用途:
cmd /K myBatch.bat
作为您的快捷方式。
【讨论】:
您可以通过修改以下注册表项为 所有 批处理文件实现此目的:HKEY_CLASSES_ROOT\batfile\shell\open\command。将值从 "%1" %* 设置为 cmd /k "%1" %* 谢谢。我喜欢这个。我已经按照建议在注册表中进行了设置。【参考方案2】:我的问题是类似的 - 如果从 Windows 资源管理器调用,我希望在最后暂停,但如果在命令窗口中没有暂停。我想出了这个。 在每个批处理文件的顶部,放置:
if "%parent%"=="" set parent=%~0
if "%console_mode%"=="" (set console_mode=1& for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set console_mode=0)
然后在最后
if "%parent%"=="%~0" ( if "%console_mode%"=="0" pause )
它处理嵌套批处理调用,您只想在原始批处理文件的末尾暂停,而不是在嵌套批处理文件中。在嵌套的批处理文件中,%parent%
已设置为原始调用者,因此它不会等于嵌套的 %~0
。如果您有调用bat2
的bat1
,它将打开在资源管理器中双击bat2 的选项-在这种情况下bat2
将在最后暂停,而如果bat1
调用bat2
,则bat2
获胜'不要在结尾暂停(只有bat1
会暂停)。
&
语句分隔符有助于避免主要功能次要的某些内容的视觉混乱。如果您不喜欢它的外观,只需将每个语句放在一个新行上。
这种方法在启动命令 (%cmdcmdline%
) 中查找 /C
作为参数之一。它假定您的批处理文件不使用 /C
选项。如果你自己使用/C
,那么你需要检查%COMSPEC%
是否出现在%cmdcmdline%
中(使用FINDSTR
)。当资源管理器启动一个 bat 文件时,它的%cmdcmdline%
包括%COMSPEC%
例如C:\Windows\System32\cmd.exe /C double_clicked_batch_file_name
。在命令窗口中,%cmdcmdline%
中只有 cmd.exe
(没有路径)。我使用CALL mybat
而不是cmd.exe /C mybat
,但您可能必须使用现有的批处理文件。
【讨论】:
这个答案很简短,易于理解,并解决了所有问题:无需更改快捷方式或注册表;如果从 cmd 手动运行,则无需暂停,否则无需暂停;只需在脚本中添加一些行并完成。作为奖励,它还处理嵌套的批处理调用。 简而言之:这个答案需要更多的支持!【参考方案3】:这是一个很好的解决方案,并考虑到批处理文件可能调用另一个批处理文件(“嵌套”)的可能性。
如果批处理文件是从“命令提示符”运行的,您可以使用 Find 来查找不应该出现的“/c”:
echo %cmdcmdline% | find /i "/c"
但是,您可以通过使用 Find 来搜索更长的字符串或批处理文件名来进行更“稳健”的测试。
如果搜索字符串中包含 (") 双引号,则“查找”命令将无法正常工作。要解决此问题,您可以使用环境变量替换来“调整”字符串,使其与 Find 配合使用:
set newcmdcmdline=%cmdcmdline:"=-%
这通常会返回:
if the batch-file is run from a "Command Prompt"
newcmdcmdline=-C:\Windows\system32\cmd.exe-
if the batch-file is run by clicking on the the batch-file
(or the batch-file shortcut) from "Windows Explorer"
newcmdcmdline=cmd /c --D:\Path\test.cmd- -
然后你可以使用“查找”来测试:
echo %newcmdcmdline% | find /i "cmd /c --"
or
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
接下来,您需要决定您是否希望“嵌套”批处理文件的行为就像您以与调用批处理文件相同的方式执行它一样,或者您是否希望嵌套批处理文件始终像它们是从“命令提示符”执行的。
考虑如果你在一个嵌套的批处理文件中运行,那么测试一下:
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
总是会失败(不匹配),因为 %newcmdcmdline% 包含最外层批处理文件的名称,而不是嵌套的批处理文件。
所以第一个解决方案对于调用批处理文件和所有嵌套批处理文件的行为都是相同的。如果你不调用任何批处理文件也很完美:
在您希望进行此测试的所有批处理文件(调用和嵌套)中,添加这些行,通常靠近批处理文件的顶部(如果您愿意,可以排除回显语句):
if not defined withincmd call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from within a Command Prompt
rem if %withincmd% EQU 0 pause
然后,在每个批处理文件的某处,添加 testshell 子函数:
goto :EOF
:testshell
rem "Nested" batch-files won't see this because withincmd is already defined
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
您只能在最外层批处理文件的顶部对“testshell”进行一次条件调用。
在某些情况下,如果从“命令提示符”执行它与通过单击批处理文件(或批处理-文件快捷方式)从“Windows 资源管理器”。因此,从“最外层”批处理文件调用的批处理文件将始终表现相同,无论它们如何运行。
为此,您有几个选择。
1) 在调用另一个批处理文件之前保存“withincmd”的值,在调用的批处理文件返回后恢复“withincmd”的值。在大多数情况下,这有点涉及。
2) 在每个批处理文件中为“withincmd”使用“全局唯一”变量名。
3) 每次您需要知道当前批处理文件的运行方式时,请执行“查找”命令。
4) 在进入批处理文件时增加一个变量并在批处理文件退出时减少它,然后仅在 count-variable=1 时测试批处理文件的运行方式
方法 3 是最简单的,但缺点是如果从自身(如递归)或另一个批处理文件调用最外层的批处理文件,则无法正确设置测试变量(withincmd)。
这里是使用方法3的方法:
在您希望进行此测试的所有批处理文件(调用和嵌套)中,添加这些行,通常靠近批处理文件的顶部(如果您愿意,可以排除回显语句):
call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from (or Nested) within a Command Prompt
rem if %withincmd% EQU 0 pause
然后,在每个批处理文件的某处,添加 testshell 子函数:
goto :EOF
:testshell
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
在这种情况下,您必须在每个批处理文件的顶部调用一次“testshell”,然后在您从调用另一个批处理文件返回后再次调用(或者每次您需要知道时调用“testshell”当前批处理文件的运行方式)。
这里是使用方法4的方法:
在您希望进行此测试的所有批处理文件(调用和嵌套)中,添加这些行,通常靠近批处理文件的顶部(如果您愿意,可以排除回显语句):
if not defined nestinglevel set nestinglevel=0
set /A nestinglevel=nestinglevel+1
call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from (or Nested) within a Command Prompt
rem if %withincmd% EQU 0 pause
然后,在每个批处理文件的某处,添加 testshell 子函数:
goto :EOF
:testshell
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
if %nestinglevel% GEQ 2 goto :EOF
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
另外,请记住在退出一个批处理文件以返回调用批处理文件时减少变量:
set /A nestinglevel=nestinglevel-1
在这种情况下,您必须在每个批处理文件的顶部调用一次“testshell”,然后在您从调用另一个批处理文件返回后再次调用(或者每次您需要知道时调用“testshell”当前批处理文件的运行方式)。
在所有情况下,测试 %withincmd% 以确定当前批处理文件的运行方式,如下所示:
if %withincmd% EQU 0 pause
if %withincmd% EQU 1 goto :EOF
【讨论】:
【参考方案4】:在文件末尾打印
pause
它将等待任意键输入
【讨论】:
不起作用。它只是运行文件,然后自动关闭窗口。 它对我有用...我发现 this blog 有 3 种方法。我尝试了暂停,它起作用了:)【参考方案5】:在批次末尾添加:
echo %CMDCMDLINE% | findstr /C:"/c">nul && pause
如果从 Windows 资源管理器运行,这将暂停,如果从命令行运行,则不执行任何操作。
解释:
从 Windows 资源管理器运行时,CMDCMDLINE 包含“/c”。 回显 %CMDCMDLINE% |将 CMDCMDLINE 的内容通过管道传输到 findstr findstr /C:"/c" 检查 CMDCMDLINE 是否包含 "/c" ">nul" 将丢弃 findstr 控制台输出 && pause 仅在 findstr 找到某些东西时才会运行【讨论】:
【参考方案6】:您可以在批处理调用中添加参数并在批处理中处理有条件的暂停语句。因此,当从命令行或 dblclick 启动时,批处理可以暂停,当使用 /nopause 参数从其他批处理调用时不会暂停。
【讨论】:
“当我从命令行调用批处理文件时,我不想传递 /nopause 参数或其他东西。”已在问题中说明。 你看过我的回复了吗?参数是“从其他批次调用时”而不是从 cmd 行调用时! 批量参数是默认方式,因为 msdos.如果您与没有管理员权限来调整注册表的开发人员共享您的脚本怎么办?这是开箱即用的方法吗?【参考方案7】:在最后的批处理文件中使用“暂停”,它将等待用户输入
HTH
【讨论】:
这将总是暂停,不仅在双击批处理文件时。【参考方案8】:暂停命令会起作用吗?
Microsoft Documentation on pause
【讨论】:
以上是关于双击时如何使Windows批处理文件暂停?的主要内容,如果未能解决你的问题,请参考以下文章