如何让Windows批处理文件在双击时暂停?

12

我已经编写了一个批处理文件来自动化一些任务。 我可以从命令窗口运行它并显示结果。 但是,如果我从资源管理器中双击它,它会立即运行并终止,因此我无法看到结果。

是否有一种方法可以使批处理文件窗口保持打开状态,直到我在双击图标启动它后进行确认关闭呢?

我不想在从命令行调用批处理文件时传递/nopause参数或其他内容。 我希望有一种解决方案,可以在不需要做任何特殊操作的情况下使用批处理文件。

谢谢。

注意:我不希望在从命令行运行时暂停!!我可能会从另一个批处理文件中调用此批处理文件执行一系列操作。在这种情况下,我不能坐在那里不断按回车键。

理想情况下,最好是在批处理文件中放置一些代码,以便可以确定它是在哪里启动的,并根据情况暂停或不暂停。

9个回答

16

用法:

cmd /K myBatch.bat
作为您的快捷方式。

10
你可以通过修改以下注册表键值HKEY_CLASSES_ROOT\batfile\shell\open\command,实现对所有批处理文件的更改。将值从"%1" %*修改为cmd /k "%1" %*。 - Dirk Vollmar
谢谢。我喜欢这个。我已经按照建议在注册表中设置了它。 - Scott Langham

10

我的问题类似 - 当从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 不相等。如果您有 bat1 调用 bat2,则可以打开在资源管理器中双击 bat2 的选项 - 在该上下文中,bat2 将在结束时暂停,而如果 bat1 调用 bat2,则 bat2 不会在结束时暂停(只有 bat1 会停顿)。

& 语句分隔符有助于避免对主要功能次要化的视觉混乱。如果你不喜欢它的外观,只需将每个语句放在新行上即可。

此方法查找启动命令(%cmdcmdline%)中的一个参数是否为 /C。它假定您的批处理文件不使用 /C 选项。如果您自己使用了 /C,那么您需要检查 %cmdcmdline% 中是否包含 %COMSPEC%(使用 FINDSTR)。当资源管理器启动批处理文件时,它的 %cmdcmdline% 包括 %COMSPEC%,例如 C:\Windows\System32\cmd.exe /C double_clicked_batch_file_name。在命令窗口中,%cmdcmdline% 中只有 cmd.exe(没有路径)。我使用 CALL mybat 而不是 cmd.exe /C mybat,但您可能需要使用现有的批处理文件。


1
这个答案简短易懂,解决了所有问题:无需更改快捷方式或注册表;如果从cmd手动运行,则无需暂停,否则需要暂停;只需在脚本中添加几行代码即可完成。作为额外的奖励,它还处理了嵌套批处理调用。简而言之:这个答案需要更多的赞! - aff

8

这里有一个解决方案,可以很好地处理批处理文件可能调用另一个批处理文件(“嵌套”)。

您可以使用Find命令查找“/c”,如果从“命令提示符”运行批处理文件,则不应该出现此命令:

echo %cmdcmdline% | find /i "/c"

但是,您可以通过使用“查找”命令搜索更长的字符串或批处理文件名来进行更“健壮”的测试。

如果搜索字符串中包含()双引号,则“查找”命令将无法正常工作。为了解决这个问题,您可以使用环境变量替换来“调整”字符串,以便使其与“查找”命令兼容:

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%包含最外层批处理文件的名称,而不是嵌套的批处理文件。

所以第一个解决方案对于调用批处理文件和所有嵌套批处理文件都会产生相同的行为。如果您不调用任何批处理文件,则完美无缺:

在您关心进行此测试的所有批处理文件(调用和嵌套)中添加这些行,通常位于批处理文件的顶部附近(如果您愿意,可以排除echo语句):

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)每次需要知道当前批处理文件是如何运行的时候,执行“Find”命令。

4)在进入批处理文件时增加一个变量并在退出批处理文件时减少它,然后仅在计数变量= 1时测试批处理文件如何运行。

方法3是最简单的,但缺点是如果最外层批处理文件是从自身(如递归)或另一个批处理文件中调用的,则测试变量(withincmd)将无法正确设置。

以下是使用方法3的方法:

在您关心进行此测试的所有批处理文件(调用和嵌套)中,添加这些行,通常位于批处理文件的顶部(如果您愿意,可以省略echo语句):

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种方法的方法:
在所有您想要进行此测试的批处理文件(包括调用和嵌套的批处理文件)中,添加以下行,通常位于批处理文件的顶部(如果愿意,可以省略echo语句):
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”)。
在所有情况下,使用“test %withincmd%”来确定当前批处理文件的运行方式,就像这样:
if %withincmd% EQU 0 pause
if %withincmd% EQU 1 goto :EOF

我非常感激你详尽的解释和更详细的查找命令,但是在使用Windows 10中的方法3时,我没有运气,即使用了setlocal enableextensionssetlocal enabledelayedexpansion - theSparky

3
在文件末尾打印。
pause

它将等待任意键输入。


4
无效。它只运行文件,然后自动关闭窗口。 - Albert T. Wong
对我有用... 我找到了这篇博客,其中提供了三种方法。我尝试了暂停的那个,它有效 :) - Joel Carneiro

2
将以下内容添加到您的批处理文件末尾:
echo %CMDCMDLINE% | findstr /C:"/c">nul && pause

如果从Windows资源管理器运行,则会暂停;如果从命令行运行,则不执行任何操作。

解释:

  • 当从Windows资源管理器运行时,CMDCMDLINE包含“/c”。
  • echo % CMDCMDLINE% | 将CMDCMDLINE的内容传输到findstr中
  • findstr / C:“/ c”检查CMDCMDLINE是否包含“/ c”
  • ">nul"将丢弃findstr控制台输出
  • && pause仅在findstr发现某些内容时运行

这个一句话真是太赞了,我给它点赞! - undefined

1

%cmdcmdline% 包含当前批处理文件的名称,如果通过鼠标双击启动(否则它只包含 CMD.exe 的路径)。

因此,在我的批处理文件的末尾,如果在 %cmdcmdline% 中找到批处理文件名 %~nx0,我会暂停执行:

echo %cmdcmdline%|findstr /c:"%~nx0" >nul
if %errorlevel% equ 0 echo.&pause

-1

你可以在批处理调用中添加参数,并有条件地处理暂停语句。因此,当从命令行或双击批处理文件启动时,批处理可以暂停;当从其他批处理文件使用 /nopause 参数调用时,则不会暂停。


1
问题中提到:“我不想在从命令行调用批处理文件时传递/nopause参数或其他参数。” - Dirk Vollmar
你看过我的回复吗?参数是“当从其他批处理文件调用时”,而不是从命令行调用! - Andrea Balducci
批处理中的参数是默认方式,自 msdos 以来就是如此。如果您将脚本分享给没有管理员权限来调整注册表的开发人员,那怎么办?这是一个开箱即用的方法吗? - Andrea Balducci

-2

在批处理文件的结尾处使用 "pause" 命令,它会等待用户输入。

希望这能帮到你。


3
这将始终暂停,不仅在双击批处理文件时暂停。 - Dirk Vollmar

-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接