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

发布于 2024-11-04 14:08:14 字数 251 浏览 0 评论 0 原文

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

if (initiated_from_explorer) then
else
endif

这可能吗?谢谢

I have a bat file that does a bunch of things and closes the cmd window which is fine when user double clicks the bat file from explorer. But if I run the bat file from a already open cmd window as in cmd>c:\myfile.bat then I do not want the bat file to close the cmd window (END) since I need to do other things. I need bat dos command code that will do something like

if (initiated_from_explorer) then
else
endif

Is this possible ? thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

转身以后 2024-11-11 14:08:14

mousio 的解决方案很好,但由于%cmdcmdline% 的值(在 %cmdcmdline% 两边带或不带双引号)。

相比之下,使用 %0 的解决方案效果很好。我使用了以下块语句,它的工作方式就像一个魅力:

IF %0 == "%~0"  pause

以下解决方案将 %~0 扩展为完全限定的路径,如果前面的解决方案不起作用(参见Alex Essilfie 的评论):

IF %0 EQU "%~dpnx0" PAUSE

但是,请注意,当

  1. .bat 文件位于%USERPROFILE% 目录,并且
  2. 您的 %USERNAME% 包含一个或多个大写字符

,因为...等等...中的 d %~dpnx0 强制您的 %USERPROFILE% 用户名小写,而普通 %0 则不会。因此,如果您的用户名包含大写字符,它们永远不会相等。 ́\_(ツ)_/́

[编辑 2021 年 6 月 18 日 - 感谢 JasonXA]

您可以通过不区分大小写的比较来解决这个小写问题(神奇的 / I):

IF /I %0 EQU "%~dpnx0" PAUSE

这可能是最好的解决方案!

mousio's solution is nice but I did not manage to make it work in an "IF" statement because of the double quotes in the value of %cmdcmdline% (with or without double quotes around %cmdcmdline%).

In constrast, the solution using %0 works fine. I used the following block statement and it works like a charm:

IF %0 == "%~0"  pause

The following solution, which expands %~0 to a fully qualified path, might also work if the previous does not (cf. Alex Essilfie's comment):

IF %0 EQU "%~dpnx0" PAUSE

However, note that this solution with %~dpnx0 fails when

  1. the .bat file is located somewhere in the %USERPROFILE% directory, and
  2. your %USERNAME% contains one or more uppercase characters

because... wait for it... the d in %~dpnx0 forces your %USERPROFILE% username to lowercase, while plain %0 does not. So they're never equal if your username contains an uppercase character. ¯\_(ツ)_/¯

[Edit 18 June 2021 - thanks to JasonXA]

You can solve this lowercase issue with case-insensitive comparison (magic /I):

IF /I %0 EQU "%~dpnx0" PAUSE

This might be the best solution of all!

夜灵血窟げ 2024-11-11 14:08:14

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

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

就我个人而言,我会选择 %cmdcmdline% 方法(而不是 %O),但请注意,这两个启动命令都可以在注册表中被覆盖......

%cmdcmdline% gives the exact command line used to start the current Cmd.exe.

  • When launched from a command console, this var is "%SystemRoot%\system32\cmd.exe".
  • When launched from explorer this var is cmd /c ""{full_path_to_the_bat_file}" ";
    this implicates that you might also check the %0 variable in your bat file, for in this case it is always the full path to the bat file, and always enclosed in double quotes.

Personally, I would go for the %cmdcmdline% approach (not %O), but be aware that both start commands can be overridden in the registry…

清欢 2024-11-11 14:08:14

从本页上找到的大部分信息得出的综合答案:

:pauseIfDoubleClicked
setlocal enabledelayedexpansion
set testl=%cmdcmdline:"=%
set testr=!testl:%~nx0=!
if not "%testl%" == "%testr%" pause
  1. 变量“testl”获取 cmd 处理器调用的完整行(根据 mousio),去掉所有讨厌的双引号。
  2. 变量“testr”采用“testl”,并进一步删除当前批处理文件名(如果存在)(如果通过双击调用批处理文件,则将是该名称)。
  3. if 语句查看“testl”和“testr”是否不同。如果是,则批处理被双击,所以暂停;如果没有,则在命令行中输入了批处理,然后继续。

当然,如果您在检测到双击时想做其他事情,则可以更改暂停。

谢谢大家。

A consolidated answer, derived from much of the information found on this page:

:pauseIfDoubleClicked
setlocal enabledelayedexpansion
set testl=%cmdcmdline:"=%
set testr=!testl:%~nx0=!
if not "%testl%" == "%testr%" pause
  1. The variable "testl" gets the full line of the cmd processor call (as per mousio), stripping out all of the pesky double quotes.
  2. The variable "testr" takes "testl" and further strips outs the name of the current batch file name if present (which it will be if the batch file was invoked with a double-click).
  3. The if statement sees if "testl" and "testr" are different. If yes, batch was double-clicked, so pause; if no, batch was typed in on command line, go on.

Naturally, if you want to do something else if you detect a double-click, you can change the pause.

Thanks everyone.

苯莒 2024-11-11 14:08:14

更少的代码,更强大:

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

  1. x 替换引号以启用文本比较,而不会破坏 IF 语句。
  2. 准确地重新创建预期的 cmdcmdline(嗯,用 x 替换 '"')。
  3. 测试不区分大小写的相等性。

结果是:

set "dclickcmdx=%comspec% /c xx%~0x x"
set "actualcmdx=%cmdcmdline:"=x%"

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

这增加了针对一般 cmd /c 的更多鲁棒性> 调用,因为资源管理器在最后一个 quote/x 之前添加了一个尴尬的额外空格(对我们有利)。如果找不到 cmdcmdline,它会正确呈现 isdoubleclicked=0

附录:

与上述方法类似,如果从资源管理器双击脚本,以下一行将暂停脚本,我将其添加到脚本的末尾以保持命令行窗口打开:(

Edit 2022。 -01-12,修复了此讨论中的引用不匹配问题

if /i "%comspec% /c ``%~0` `" equ "%cmdcmdline:"=`%" pause
if /i "%comspec% /c %~0 " equ "%cmdcmdline:"=%" pause

Less code, more robust:

Build upon the other answers, I find the most robust approach to:

  1. Replace quotes with x to enable text comparison without breaking the IF statement.
  2. Recreate the expected cmdcmdline exactly (well, with '"' replaced by x).
  3. Test for case-insensitive equality.

The result is:

set "dclickcmdx=%comspec% /c xx%~0x x"
set "actualcmdx=%cmdcmdline:"=x%"

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

This adds more robustness against general cmd /c calls, since Explorer adds an awkward extra space before the last quote/x (in our favor). If cmdcmdline isn't found, it correctly renders isdoubleclicked=0.

Addendum:

Similarly to the above method, the following one-liner will pause a script if it was double-clicked from explorer. I add it to the end of my scripts to keep the command-line window open:

(Edit 2022-01-12, fixed quote mismatching from this discussion)

if /i "%comspec% /c ``%~0` `" equ "%cmdcmdline:"=`%" pause

if /i "%comspec% /c %~0 " equ "%cmdcmdline:"=%" pause

萌逼全场 2024-11-11 14:08:14

使用 exit /b 0,而不是 exit

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

Use exit /b 0, not exit

The former will exit all the way if launched from Windows Explorer, but return to the console if launched from the command line.

天荒地未老 2024-11-11 14:08:14

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

You can add a command line parameter when running from a CMD window that won't exist when the file is double-clicked. If there is no parameter, close the window. If there is, don't close it. You can test the parameter using %1

属性 2024-11-11 14:08:14

这不仅是可能的,而且您想要的行为是批处理文件执行的正常行为,除非您做了一些“特殊”的事情:

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

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

It's not only possible, but your desired behavior is the normal behavior of batch file execution, unless you do something 'special':

  • when executing a batch file by double-clicking it in Explorer, the cmd window will close when it's done;
  • when the batch file is executed from the command line, it simply returns to the command line prompt when complete - the window is not closed;

So I think the question that needs to be answered is what are you doing in the batch file that causes the command window to close when you execute it by the command line?

半世晨晓 2024-11-11 14:08:14

将其粘贴到 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 和有空格。因此,逻辑首先删除所有引号,然后删除所有空格..因为有时删除引号后会有额外的空格。

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

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

但是您可以将此部分替换

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

为类似的内容

set CALLED_WITH_CMD_C=YES

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

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

Paste this at the beginning of your BAT or CMD script and maybe change what happens in the 'if' clause:

:: 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

What this does, is if the user either double-clicks or calls this script using "cmd /c" it will re-launch with "cmd /k" which will leave the session open after the command finishes. This allows the user to EXIT or maybe do something else.

The reason for doing it this way rather than the other ways explained in this answer is because I've found situations that still even with using the quotes or other symbols, the IF statement would barf with certain situations of the QUOTES and the /c and with spaces. So the logic first removes all QUOTES and then removes all spaces.. because SOMETIMES there is an extra space after removing the 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

The point of the && exit || exit is so that if the ERRORLEVEL before exiting is 0 (success) it then stops running, but also if it is non 0 (some failure) it also stops running.

But you can replace this part:

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

with something like

set CALLED_WITH_CMD_C=YES

and then make up your own differences in the rest of your script. You would have to then move or remove the endlocal.

The '@' symbol at front just prevents the echo, which you can have if you want to test.
Do not use echo on or echo off as it changes the setting and affects all subsequent scripts that call yours.

锦爱 2024-11-11 14:08:14

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

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

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

这里没有原创内容,只是提供一个工作示例)

Like @anishsane I too wanted a pause statement if launched from explorer, but not when launched from a command window.

Here's what worked for me, based upon @mousio's answer above:

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

(Nothing original here, just providing a working example)

心意如水 2024-11-11 14:08:14

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

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

@dlchambers was close but set didn't work since cmdcmdline isn't a defined environment variable in some cases, but this version based on his works great for me:

echo %cmdcmdline% | findstr /i pushd >nul
if errorlevel 1 pause
五里雾 2024-11-11 14:08:14

阅读完建议后,这就是我的做法:

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
)

..但是关于Powershell的问题@Ruben Bartelink 提及未解决:

从 Powershell 运行 ./batch.cmd 在底层使用 cmd /c

after reading through the suggestions, this is what I went with:

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=

which conditionally sets the variable: CMD_INITIATED_FROM_EXPLORER

..and can subsequently be used as needed:

if defined CMD_INITIATED_FROM_EXPLORER (
  echo.
  pause
)

..but the issue regarding Powershell that @Ruben Bartelink mentions isn't solved:

running ./batch.cmd from Powershell uses cmd /c under the hood

枕头说它不想醒 2024-11-11 14:08:14

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

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

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

You also can check for SESSIONNAME environment variable.

As you see here that variable typically isn't set in Explorer window. When invoking from cmd it SESSIONNAME is set to Console. I can confirm this for Windows 10.

Unfortunately behaviour seems to be changeable: https://support.microsoft.com/de-de/help/2509192/clientname-and-sessionname-enviroment-variable-may-be-missing

歌入人心 2024-11-11 14:08:14

(部分)与已接受的答案 AToW(re %cmdcmdline%)和最佳答案 AToW(re if /i %0 equ "%~dpnx0")相反)在Win10中是:

  • 在CMD中:

    • *.cmd 中(此处为 _pauseIfRunFromGUI.cmd):

      “C:\Windows\System32\cmd.exe”
      
      if /I _pauseIfRunFromGUI[.cmd] EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      如果在 cmd 行上输入,则出现

      .cmd,如果使用 Tab 完成,则会出现这种情况。

    • 在由 *.cmd调用*.cmd (_pauseIfRunFromGUI.cmd) 中代码>:

      “C:\Windows\System32\cmd.exe”
      
      if /I _pauseIfRunFromGUI[.cmd] EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      同上。

      如果通过 call _pauseIfRunFromGUI.cmd 调用,则存在

      .cmd

    无论如何,比较结果都是预期的

  • 来自 GUI:

    (桌面上的资源管理器和链接)

    • 在从 GUI 启动的 *.cmd(此处为 _pauseIfRunFromGUI.cmd)中:

      C:\WINDOWS\system32\cmd.exe /c ""C:\Users\Geri\_pauseIfRunFromGUI.cmd" "
      
      if /I "C:\Users\Geri\_pauseIfRunFromGUI.cmd" EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      这个与接受的答案 AToW 不同,后者只是 cmd /c ""..." "_!

      比较结果为预期的true

    • 在由 *.cmd调用*.cmd (_pauseIfRunFromGUI.cmd) 中 code>(此处为 calling.cmd),从 GUI 启动:

      C:\WINDOWS\system32\cmd.exe /c ""C:\Users\Geri\calling.cmd" "
      
      if /I _pauseIfRunFromGUI[.cmd] EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      与上面不同,因为调用.cmd是在cmdcmdline中,当然,不是在其中评估它的地方(_pauseIfRunFromGUI.cmd).

      如果通过 calling.cmd 内的 call _pauseIfRunFromGUI.cmd 调用,则存在

      .cmd

      比较结果为,这不是预期的!

如果比较更改为:

if /i "%cmdcmdline:~0,31%"=="C:\WINDOWS\system32\cmd.exe /c " echo: & pause

一切都按预期进行。

(Partly) Contrary and in addition to the accepted answer AToW (re %cmdcmdline%) and the top answer AToW (re if /i %0 equ "%~dpnx0") in Win10 it is:

  • in CMD:

    • in a *.cmd (here _pauseIfRunFromGUI.cmd):

      "C:\Windows\System32\cmd.exe"
      
      if /I _pauseIfRunFromGUI[.cmd] EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      .cmd is present if entered on the cmd line, which happens if you complete with Tab.

    • in a *.cmd (_pauseIfRunFromGUI.cmd) that's called by a *.cmd:

      "C:\Windows\System32\cmd.exe"
      
      if /I _pauseIfRunFromGUI[.cmd] EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      Same as above.

      .cmd is present if called via call _pauseIfRunFromGUI.cmd.

    In any way the comparison evaluates to false which is intended.

  • from GUI:

    (Explorer and link on Desktop)

    • in a *.cmd (here _pauseIfRunFromGUI.cmd) that's launched from the GUI:

      C:\WINDOWS\system32\cmd.exe /c ""C:\Users\Geri\_pauseIfRunFromGUI.cmd" "
      
      if /I "C:\Users\Geri\_pauseIfRunFromGUI.cmd" EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      This one is different to the accepted answer AToW which says just cmd /c ""..." "_!

      The comparison evaluates to true which is intended.

    • in a *.cmd (_pauseIfRunFromGUI.cmd) that's called by a *.cmd (here calling.cmd) that's launched from the GUI:

      C:\WINDOWS\system32\cmd.exe /c ""C:\Users\Geri\calling.cmd" "
      
      if /I _pauseIfRunFromGUI[.cmd] EQU "C:\Users\Geri\_pauseIfRunFromGUI.cmd"
      

      Different to above, since calling .cmd is in cmdcmdline, of course, not the one in which it is evaluated (_pauseIfRunFromGUI.cmd).

      .cmd is present if called via call _pauseIfRunFromGUI.cmd within calling.cmd.

      The comparison evaluates to false which is not intended!

If the comparison is changed to:

if /i "%cmdcmdline:~0,31%"=="C:\WINDOWS\system32\cmd.exe /c " echo: & pause

everything works as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文