通过双击或从cmd窗口检测bat文件是否正在运行

时间:2011-05-02 16:44:27

标签: windows cmd

我有一个bat文件可以执行大量操作并关闭cmd窗口,当用户从资源管理器中双击bat文件时这很好。但是,如果我从cmd> c:\ myfile.bat中已经打开的cmd窗口运行bat文件,那么我不希望bat文件关闭cmd窗口(END),因为我需要做其他事情。我需要bat dos命令代码,它将执行类似

的操作
if (initiated_from_explorer) then
else
endif

这可能吗?感谢

12 个答案:

答案 0 :(得分:13)

%cmdcmdline%给出了用于启动当前Cmd.exe的确切命令行。

  • 从命令控制台启动时,此变量为"%SystemRoot%\system32\cmd.exe"
  • 从资源管理器启动时,此变量为cmd /c ""{full_path_to_the_bat_file}" ";
    这意味着您还可以检查bat文件中的%0变量,对于,在这种情况下它始终是bat​​文件的完整路径,并且始终用双引号括起来。

就个人而言,我会采用%cmdcmdline%方法(而不是%O),但要注意两个启动命令都可以在注册表中重写...

答案 1 :(得分:13)

来自“mousio”的解决方案很好;但是,由于%cmdcmdline%的值为双引号(在%cmdcmdline%附近有或没有双引号),我个人无法在“IF”语句中使其工作。

但是,使用%0的解决方案可以正常工作。我使用了以下块语句,它就像一个魅力:

IF %0 == "%~0"  pause

如果以前的解决方案没有(Alex Essilfie的礼貌),以下解决方案也可能有效:

IF %0 EQU "%~dpnx0" PAUSE

希望它可以提供帮助。

答案 2 :(得分:5)

综合答案,源自此页面上的大部分信息:

:pauseIfDoubleClicked
setlocal enabledelayedexpansion
set testl=%cmdcmdline:"=%
set testr=!testl:%~nx0=!
if not "%testl%" == "%testr%" pause
  1. 变量" testl"获取cmd处理器调用的完整行(按照mousio),删除所有令人讨厌的双引号。
  2. 变量" testr"需要"测试"并且进一步剥离当前批处理文件名的名称(如果存在则通过双击调用批处理文件)。
  3. if语句查看" testl"和" testr"是不同的。如果是,则双击批次,暂停;如果不是,则在命令行输入批处理,继续。
  4. 当然,如果你想检测双击,你可以做其他事情,你可以改变暂停。

    谢谢大家。

答案 3 :(得分:3)

您可以在从CMD窗口运行时添加命令行参数,该窗口在双击文件时不存在。如果没有参数,请关闭窗口。如果有,请不要关闭它。您可以使用%1

测试参数

答案 4 :(得分:2)

这不仅可行,而且您希望的行为是批处理文件执行的正常行为,除非您执行“特殊”操作:

  • 在资源管理器中双击执行批处理文件时,cmd窗口将在完成时关闭;
  • 当从命令行执行批处理文件时,它只是在完成时返回到命令行提示符 - 窗口未关闭;

所以我认为需要回答的问题是你在批处理文件中做了什么导致命令窗口在命令行执行时关闭?

答案 5 :(得分:2)

使用exit /b 0,而不是exit

如果从Windows资源管理器启动,前者将一直退出,但如果从命令行启动,则返回控制台。

答案 6 :(得分:2)

更少的代码,更强大:

在其他答案的基础上,我找到了最可靠的方法:

  1. x替换引号以启用文本比较而不会破坏IF语句。
  2. 完全重新创建预期的cmdcmdline(好,用x替换为“”)。
  3. 测试不区分大小写的相等性。

结果是:

set "dclickcmdx=%systemroot%\system32\cmd.exe /c xx%~0x x"
set "actualcmdx=%cmdcmdline:"=x%"

set isdoubleclicked=0
if /I "%dclickcmdx%" EQU "%actualcmdx%" (
    set isdoubleclicked=1
)

这增加了针对常规cmd /c调用的稳定性,因为资源管理器在最后一个引号/ x之前添加了一个尴尬的额外空间(对我们有利)。如果找不到cmdcmdline,它将正确呈现isdoubleclicked=0

答案 7 :(得分:1)

与@anishsane一样,如果从资源管理器启动,我也想要一个暂停语句,但是从命令窗口启动时却不需要。

根据@ mousio上面的回答,这对我有用:

@SET cmdcmdline|FINDSTR /b "cmdcmdline="|FINDSTR /i pushd >nul
@IF ERRORLEVEL 1 (
    @echo.
    @echo Press ENTER when done
    @pause > nul
)

(这里没有任何原创,仅提供一个工作示例)

答案 8 :(得分:0)

将其粘贴在BAT或CMD脚本的开头,并可能更改“if”子句中发生的情况:

:: To leave command window open if script run from Windows explorer.
@setlocal
@set x=%cmdcmdline:"=%
@set x=%x: =%
@set y=%x:cmd/c=%
@if "%x%" neq "%y%" cmd /k %0 %* && exit || exit
@endlocal

这样做,如果用户双击或使用“cmd / c”调用此脚本,它将使用“cmd / k”重新启动,这将在命令完成后使会话保持打开状态。这允许用户退出或者做其他事情。

这样做的原因而不是在这个答案中解释的其他方式是因为我发现情况仍然使用引号或其他符号,IF语句会在某些情况下使用QUOTES和/ c和空格。所以逻辑首先删除所有QUOTES,然后删除所有空格..因为删除引号后有一些额外的空格。

set x=%cmdcmdline:"=%       <-- removes all quotes
set x=%x: =%                <-- removes all spaces
set y=%x:cmd/c=%            <-- removes  cmd/c  from the string saving it to  y

&amp;&amp;&amp;退出|| exit是这样的,如果退出前的ERRORLEVEL为0(成功),则它会停止运行,但如果它不为0(某些失败),它也会停止运行。

但你可以替换这部分:

cmd /k %0 %* && exit || exit

类似

set CALLED_WITH_CMD_C=YES

然后在脚本的其余部分中弥补自己的差异。然后你必须移动或删除endlocal。

前面的'@'符号可以防止回声,如果你想测试,你可以拥有回声。 不要使用echo on或echo off,因为它会更改设置并影响调用你的所有后续脚本。

答案 9 :(得分:0)

@dlchambers很接近但是没有设置,因为cmdcmdline在某些情况下不是一个定义的环境变量,但这个版本基于他的作品对我很有用:

echo %cmdcmdline% | findstr /i pushd >nul
if errorlevel 1 pause

答案 10 :(得分:0)

阅读完建议之后,这就是我的目标:

set __cmdcmdline=%cmdcmdline%
set __cmdcmdline=%__cmdcmdline:"=%
set __cmdcmdline=%__cmdcmdline: =%
set __cmdcmdline=%__cmdcmdline:~0,5%
if "%__cmdcmdline%"=="cmd/c" set CMD_INITIATED_FROM_EXPLORER=1
set __cmdcmdline=

有条件地设置变量:CMD_INITIATED_FROM_EXPLORER

..随后可以根据需要使用:

if defined CMD_INITIATED_FROM_EXPLORER (
  echo.
  pause
)

..但是@Ruben Bartelink提到的关于Powershell的问题没有解决:

  

从Powershell运行./batch.cmd使用引擎盖下的cmd /c

答案 11 :(得分:0)

您还可以检查SESSIONNAME环境变量。

正如您在此处看到的那样,通常不会在资源管理器窗口中设置变量。从cmd调用时,它的SESSIONNAME设置为Console。我可以在Windows 10上确认这一点。

不幸的是,行为似乎可以改变:https://support.microsoft.com/de-de/help/2509192/clientname-and-sessionname-enviroment-variable-may-be-missing