25
votes

Is there a way for a batch file (in this case, running on Windows XP) to determine whether it was launched from a command line (i.e. inside a console window) or launched via the shell (e.g. by double-clicking)?

I have a script which I'd like to have pause at certain points when run via the shell, but not when run at a command line. I've seen a similar question on SO, but am unable to use the same solution for two reasons: first, whether or not it pauses needs to be dependent on multiple factors, only one of which is whether it was double-clicked. Second, I'll be distributing this script to others on my team and I can't realistically ask all of them to make registry changes which will affect all scripts.

Is this possible?

4
The other answer didn't suggest a registry change. Only changing the command line that gets executed on a shortcut. Granted, that won't help you much if you double-click the actual batch file. - Joey
@Joey — You're right; I was conflating the answer and its first comment. ;-) - Ben Blank

4 Answers

36
votes

Found one :-) – After desperately thinking of what cmd might do when run interactively but not when launching a batch file directly ... I finally found one.

The pseudo-variable %cmdcmdline% contains the command line that was used to launch cmd. In case cmd was started normally this contains something akin to the following:

"C:\Windows\System32\cmd.exe"

However, when launching a batch file it looks like this:

cmd /c ""C:\Users\Me\test.cmd" "

Small demo:

@echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1
if defined DOUBLECLICKED pause

This way of checking might not be the most robust, though, but /c should only be present as an argument if a batch file was launched directly.

Works on my machine

Tested here on Windows 7 x64. It may or may not work, break, do something weird, eat children (might be a good thing) or bite you in the nose.

10
votes

A consolidated answer, derived from much of the information found on this page (and some other stack overflow pages with similar questions). This one does not rely on detecting /c, but actually checks for the name of the script in the command line. As a result this solution will not pause if you double-clicked on another batch and then called this one; you had to double-click on this particular batch file.

: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, 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 (or called from another batch file), go on.

Edit: The same can be done in a single line:

echo %cmdcmdline% | findstr /i /c:"%~nx0" && set standalone=1

In plain English, this

  • pipes the value of %cmdcmdline% to findstr, which then searches for the current script name
  • %0 contains the current script name, of course only if shift has not been called beforehand
  • %~nx0 extracts file name and extension from %0
  • >NUL 2>&1 mutes findstr by redirecting any output to NUL
  • findstr sets a non-zero errorlevel if it can't find the substring in question
  • && only executes if the preceding command returned without error
  • as a consequence, standalone will not be defined if the script was started from the command line

Later in the script we can do:

if defined standalone pause
2
votes

One approach might be to create an autoexec.nt file in the root of c:\ that looks something like:

@set nested=%nested%Z

In your batch file, check if %nested% is "Z" - if it is "Z" then you've been double-clicked, so pause. If it's not "Z" - its going to be "ZZ" or "ZZZ" etc as CMD inherits the environment block of the parent process.

-Oisin

0
votes

A little more information...

I start with a batch-file (test.cmd) that contains:

@echo %cmdcmdline%

If I double-click the "test.cmd" batch-file from within Windows Explorer, the display of echo %cmdcmdline% is:

cmd /c ""D:\Path\test.cmd" "

When executing the "test.cmd" batch-file from within a Command Prompt window, the display of
echo %cmdcmdline% depends on how the command window was started...

If I start "cmd.exe" by clicking the "Start-Orb" and "Command Prompt" or if I click "Start-Orb" and execute "cmd.exe" from the search/run box. Then I execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:

"C:\Windows\system32\cmd.exe"

Also, for me, if I click "Command Prompt" from the desktop shortcut, then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is also:

"C:\Windows\system32\cmd.exe"

But, if I "Right-Click" inside a Windows Explorer window and select "Open Command Prompt Here", then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:

"C:\Windows\System32\cmd.exe" /k ver

So, just be careful, if you start "cmd.exe" from a shortcut that contains a "/c" in the "Target" field (unlikely), then the test in the previous example will fail to test this case properly.