通过双击或从cmd窗口检测bat文件是否正在运行
我有一个bat 文件,它可以执行很多操作并关闭cmd 窗口,当用户从资源管理器中双击bat 文件时就可以了。但是,如果我从已经打开的cmd窗口运行bat文件,如cmd>c:\myfile.bat,那么我不希望bat文件关闭cmd窗口(END),因为我需要做其他事情。我需要 bat dos 命令代码来执行类似
if (initiated_from_explorer) then
else
endif
这可能吗?谢谢
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
mousio 的解决方案很好,但由于
%cmdcmdline%
的值(在%cmdcmdline%
两边带或不带双引号)。相比之下,使用
%0
的解决方案效果很好。我使用了以下块语句,它的工作方式就像一个魅力:以下解决方案将
%~0
扩展为完全限定的路径,如果前面的解决方案不起作用(参见Alex Essilfie 的评论):但是,请注意,当
%USERPROFILE%
目录,并且%USERNAME%
包含一个或多个大写字符,因为...等等...中的
d
%~dpnx0
强制您的%USERPROFILE%
用户名小写,而普通%0
则不会。因此,如果您的用户名包含大写字符,它们永远不会相等。́\_(ツ)_/́
[编辑 2021 年 6 月 18 日 - 感谢 JasonXA]
您可以通过不区分大小写的比较来解决这个小写问题(神奇的
/ I
):这可能是最好的解决方案!
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:The following solution, which expands
%~0
to a fully qualified path, might also work if the previous does not (cf. Alex Essilfie's comment):However, note that this solution with
%~dpnx0
fails when%USERPROFILE%
directory, and%USERNAME%
contains one or more uppercase charactersbecause... 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
):This might be the best solution of all!
%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."%SystemRoot%\system32\cmd.exe"
.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…从本页上找到的大部分信息得出的综合答案:
当然,如果您在检测到双击时想做其他事情,则可以更改暂停。
谢谢大家。
A consolidated answer, derived from much of the information found on this page:
Naturally, if you want to do something else if you detect a double-click, you can change the pause.
Thanks everyone.
更少的代码,更强大:
在其他答案的基础上,我找到了最强大的方法:
x
替换引号以启用文本比较,而不会破坏 IF 语句。结果是:
这增加了针对一般 cmd /c 的更多鲁棒性> 调用,因为资源管理器在最后一个 quote/x 之前添加了一个尴尬的额外空格(对我们有利)。如果找不到
cmdcmdline
,它会正确呈现isdoubleclicked=0
。附录:
与上述方法类似,如果从资源管理器双击脚本,以下一行将暂停脚本,我将其添加到脚本的末尾以保持命令行窗口打开:(
Edit 2022。 -01-12,修复了此讨论中的引用不匹配问题)
Less code, more robust:
Build upon the other answers, I find the most robust approach to:
x
to enable text comparison without breaking the IF statement.x
).The result is:
This adds more robustness against general
cmd /c
calls, since Explorer adds an awkward extra space before the last quote/x (in our favor). Ifcmdcmdline
isn't found, it correctly rendersisdoubleclicked=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)
使用
exit /b 0
,而不是exit
如果从 Windows 资源管理器启动,前者将一路退出,但如果从命令行启动,则返回到控制台。
Use
exit /b 0
, notexit
The former will exit all the way if launched from Windows Explorer, but return to the console if launched from the command line.
您可以在从 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
这不仅是可能的,而且您想要的行为是批处理文件执行的正常行为,除非您做了一些“特殊”的事情:
所以我认为需要回答的问题是你在批处理文件中做了什么导致当你通过命令行执行它时命令窗口关闭?
It's not only possible, but your desired behavior is the normal behavior of batch file execution, unless you do something 'special':
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?
将其粘贴到 BAT 或 CMD 脚本的开头,也许可以更改“if”子句中发生的情况:
它的作用是,如果用户双击或使用“cmd /c”调用此脚本,它将重新启动使用“cmd /k”,这将使会话在命令完成后保持打开状态。这允许用户退出或者做其他事情。
这样做的原因而不是这个答案中解释的其他方法是因为我发现即使使用引号或其他符号,IF语句仍然会在某些情况下呕吐 QUOTES 和 /c 和有空格。因此,逻辑首先删除所有引号,然后删除所有空格..因为有时删除引号后会有额外的空格。
&& 的要点退出|| exit 是这样的,如果退出前的 ERRORLEVEL 为 0(成功),则它会停止运行,但如果它为非 0(某些失败),它也会停止运行。
但是您可以将此部分替换
为类似的内容
,然后在脚本的其余部分中弥补您自己的差异。然后您必须移动或删除 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:
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.
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:
with something like
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.
就像@anishsane一样,如果从资源管理器启动,我也想要一个暂停语句,但从命令窗口启动时则不需要。
根据上面 @mousio 的回答,这对我有用:(
这里没有原创内容,只是提供一个工作示例)
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:
(Nothing original here, just providing a working example)
@dlchambers 很接近,但设置不起作用,因为 cmdcmdline 在某些情况下不是定义的环境变量,但这个基于他的版本对我来说非常有用:
@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:
阅读完建议后,这就是我的做法:
有条件地设置变量:
CMD_INITIATED_FROM_EXPLORER
..并且随后可以根据需要使用:
..但是关于Powershell的问题@Ruben Bartelink 提及未解决:
after reading through the suggestions, this is what I went with:
which conditionally sets the variable:
CMD_INITIATED_FROM_EXPLORER
..and can subsequently be used as needed:
..but the issue regarding Powershell that @Ruben Bartelink mentions isn't solved:
您还可以检查
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 toConsole
. 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
(部分)与已接受的答案 AToW(re
%cmdcmdline%
)和最佳答案 AToW(reif /i %0 equ "%~dpnx0"
)相反)在Win10中是:在CMD中:
在
*.cmd
中(此处为_pauseIfRunFromGUI.cmd
):如果在 cmd 行上输入,则出现
.cmd
,如果使用 Tab 完成,则会出现这种情况。在由
*.cmd
代码>:调用
的*.cmd
(_pauseIfRunFromGUI.cmd
) 中同上。
如果通过
call _pauseIfRunFromGUI.cmd
调用,则存在.cmd
。无论如何,比较结果都是预期的假。
来自 GUI:
(桌面上的资源管理器和链接)
在从 GUI 启动的
*.cmd
(此处为_pauseIfRunFromGUI.cmd
)中:这个与接受的答案 AToW 不同,后者只是
cmd /c ""..." "
_!比较结果为预期的true。
在由
*.cmd
code>(此处为调用
的*.cmd
(_pauseIfRunFromGUI.cmd
) 中calling.cmd
),从 GUI 启动:与上面不同,因为
调用.cmd
是在cmdcmdline
中,当然,不是在其中评估它的地方(_pauseIfRunFromGUI.cmd
).如果通过
calling.cmd
内的call _pauseIfRunFromGUI.cmd
调用,则存在.cmd
。比较结果为假,这不是预期的!
如果比较更改为:
一切都按预期进行。
(Partly) Contrary and in addition to the accepted answer AToW (re
%cmdcmdline%
) and the top answer AToW (reif /i %0 equ "%~dpnx0"
) in Win10 it is:in CMD:
in a
*.cmd
(here_pauseIfRunFromGUI.cmd
):.cmd
is present if entered on the cmd line, which happens if you complete with Tab.in a
*.cmd
(_pauseIfRunFromGUI.cmd
) that'scall
ed by a*.cmd
:Same as above.
.cmd
is present if called viacall _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: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'scall
ed by a*.cmd
(herecalling.cmd
) that's launched from the GUI:Different to above, since
calling .cmd
is incmdcmdline
, of course, not the one in which it is evaluated (_pauseIfRunFromGUI.cmd
)..cmd
is present if called viacall _pauseIfRunFromGUI.cmd
withincalling.cmd
.The comparison evaluates to false which is not intended!
If the comparison is changed to:
everything works as expected.