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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5859854/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 16:46:27  来源:igfitidea点击:

Detect if bat file is running via double click or from cmd window

windowscmd

提问by Gullu

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

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

if (initiated_from_explorer) then
else
endif

Is this possible ? thanks

这可能吗 ?谢谢

采纳答案by mousio

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

%cmdcmdline%给出用于启动当前 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 %0variable in your bat file, for in this caseit is always the full path to the bat file, and always enclosed in double quotes.
  • 从命令控制台启动时,此变量为"%SystemRoot%\system32\cmd.exe".
  • 当从资源管理器启动时,这个 var 是cmd /c ""{full_path_to_the_bat_file}" "
    这意味着您可能还会检查%0bat 文件中的变量,因为在这种情况下,它始终是 bat 文件的完整路径,并且始终用双引号括起来。

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

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

回答by Jean-Francois T.

Solution from "mousio" is nice; however, I personally 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%).

“mousio”的解决方案很好;然而,我个人并没有设法让它在“IF”语句中工作,因为值中的双引号%cmdcmdline%(带或不带双引号%cmdcmdline%)。

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

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

IF %0 == "%~0"  pause

The following solution might also work if the previous does not (courtersy of Alex Essilfie):

如果以前的解决方案不起作用,以下解决方案也可能有效(亚历克斯·埃西尔菲提供):

IF %0 EQU "%~dpnx0" PAUSE

Hope it can help.

希望它能有所帮助。

回答by DocOc

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.
  1. 变量“testl”获取 cmd 处理器调用的完整行(根据 mousio),去掉所有讨厌的双引号。
  2. 变量“testr”采用“testl”并进一步删除当前批处理文件的名称(如果存在)(如果双击调用批处理文件,它将是)。
  3. if 语句查看“testl”和“testr”是否不同。如果是,批处理被双击,所以暂停;如果不是,批处理是在命令行中输入的,继续。

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

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

Thanks everyone.

谢谢大家。

回答by Dusty

Use exit /b 0, not exit

使用exit /b 0,不exit

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

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

回答by Ken White

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

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

回答by Michael Burr

It's not only possible, but your desired behavior is the normalbehavior 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;
  • 在资源管理器中双击执行批处理文件时,cmd窗口将在完成后关闭;
  • 当从命令行执行批处理文件时,它会在完成后简单地返回到命令行提示符——窗口没有关闭;

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?

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

回答by dlchambers

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

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

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

根据上面@mousio 的回答,以下是对我有用的方法:

@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)

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

回答by Simon Streicher

Less code, more robust:

更少的代码,更健壮:

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

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

  1. Replace quotes with xto 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.
  1. 将引号替换为x在不破坏 IF 语句的情况下启用文本比较。
  2. 准确地重新创建预期的 cmd cmdline(好吧,用 替换 '"' x)。
  3. 测试不区分大小写的相等性。

The result is:

结果是:

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
)

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

这增加了对一般cmd /c调用的鲁棒性,因为资源管理器在最后一个引号/x 之前添加了一个笨拙的额外空间(对我们有利)。如果cmdcmdline没有找到,它会正确呈现isdoubleclicked=0.

回答by user2415376

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

将其粘贴到 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

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.

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

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.

这样做的原因而不是这个答案中解释的其他方式是因为我发现即使使用引号或其他符号的情况,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

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.

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

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.

然后在脚本的其余部分弥补您自己的差异。然后您必须移动或删除 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.

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

回答by osm0sis

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

@dlcambers 很接近,但 set 不起作用,因为在某些情况下 cmdcmdline 不是定义的环境变量,但这个基于他的作品的版本对我来说很棒:

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