Detect if bat file is running via double click or from cmd window
Less code, more robust:
Build upon the other answers, I find the most robust approach to:
- Replace quotes with
x
to enable text comparison without breaking the IF statement. - Recreate the expected cmdcmdline exactly (well, with '"' replaced by
x
). - 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
%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…
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
- the .bat file is located somewhere in the
%USERPROFILE%
directory, and - 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!
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
- The variable "testl" gets the full line of the cmd processor call (as per mousio), stripping out all of the pesky double quotes.
- 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).
- 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.