Reputation: 3529
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
Upvotes: 43
Views: 14475
Reputation: 12960
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
%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
):
IF /I %0 EQU "%~dpnx0" PAUSE
This might be the best solution of all!
Upvotes: 23
Reputation: 2826
Build upon the other answers, I find the most robust approach to:
x
to enable text comparison without breaking the IF statement.x
).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
.
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
Upvotes: 10
Reputation: 14782
(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 call
ed 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 call
ed 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.
Upvotes: 0
Reputation: 544
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
Upvotes: 0
Reputation: 63
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 usescmd /c
under the hood
Upvotes: 0
Reputation: 1
@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
Upvotes: 0
Reputation: 755
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
Naturally, if you want to do something else if you detect a double-click, you can change the pause.
Thanks everyone.
Upvotes: 9
Reputation: 3752
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)
Upvotes: 1
Reputation: 3860
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.
Upvotes: 1
Reputation: 51
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.
Upvotes: 5
Reputation: 10337
%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}" "
;%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…
Upvotes: 17
Reputation: 340466
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?
Upvotes: 2
Reputation: 125747
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
Upvotes: 3