Question mark get url encoded in windows batch file - windows

I'm having trouble with a batch script that worked a few days ago, but now doesnt work, even though no changes has been made!
I believe something has changed in the system without my knowledge.
The expected link is:
order.htm?order=12345
But it becomes like this: (notice the question mark becomes %3F)
order.htm%3Forder=12345
The code is as follows:
#echo off
echo.
set "drive=%~d0"
set "runningDir=%~dp0"
:start
ClS
Echo.
Set /P Job=Enter number:^>
#echo off
if exist c:\"Program Files (x86)"\Google\Chrome\Application\chrome.exe goto program_files_x86
:program_files_x86
start c:\"Program Files (x86)"\Google\Chrome\Application\chrome.exe --disable-print-preview --ignore-certificate-errors --disable-web-security --user-data-dir --allow-file-access-from-files %runningDir%\order.htm?order=%job%
goto end
:end
goto start
Any suggestions?
Best Regards
Niclas

Double quotes should be usually used around entire folder/file string and not just parts of it.
Command START interprets first double quoted string as title for the new command process. Therefore on starting a GUI application an empty title string specified with "" should be used on START command line to avoid interpreting the double quoted file name with path of the application to execute as title string.
The batch file path referenced with %~dp0 always ends with a backslash. Therefore don't specify an extra backspace after this string or an environment variable like runningDir with path of batch file. By the way: The current directory on running a batch file can be different to directory of batch file. For that reason the name runningDir is not good as misleading. A better name for the environment variable is BatchPath.
It is possible to use start as label in a batch file. But it is not advisable to do that because of command START which makes it difficult to search for label respectively search for command. It is better to use a label like Begin.
In an url the directory separator is / and therefore each backslash (directory separator on Windows) in batch file path should be substituted by a slash.
The url should start with the protocol like http:// (Hypertext Transfer Protocol) and should be enclosed completely in double quotes.
And last echo/ or echo( is better than echo. for printing a blank line, see Difference between Echo[Special Character] for details.
The rewritten batch code:
#echo off
echo/
set "BatchPath=%~dp0"
set "BatchPath=%BatchPath:\=/%"
:Begin
clS
echo/
set /P "Job=Enter number: "
if exist "%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe" goto program_files_x86
:program_files_x86
start "" "%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe" --disable-print-preview --ignore-certificate-errors --disable-web-security --user-data-dir --allow-file-access-from-files "http://%BatchPath%order.htm?order=%Job%"
goto end
:end
goto Begin
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
cls /?
echo /?
goto /?
if /?
set /?
start /?

Related

How do I format Tesseract-OCR language settings within a .bat file's "for" command

I'm new to Windows cmd and .bat, and to Tesseract. But thanks to this list I've managed a couple of successes.
My first success was this cmd-window line:
tesseract.exe -l eng+lat+ita D:\TIFs\Convivio.tiff D:\TIFs\Convivio
My next success was the .bat file:
:Start
#Echo off
ECHO.
ECHO This is a batch file
ECHO.
PAUSE
BREAK=ON
Set _SourcePath=D:\temp\TIFs\*.tif
Set _OutputPath=D:\temp\TIFs\
Set _Tesseract="D:\temp\Tesseract-OCR\tesseract.exe"
:Convert
For %%A in (%_SourcePath%) Do Echo Converting "%%A"...... &"D:\temp\Tesseract-OCR\tesseract.exe" "%%A" "%_OutputPath%%%~nA"
PAUSE
:End
Set "_SourcePath="
Set "_OutputPath="
Set "_Tesseract="
The problem now is how to include in the .bat file that"-l eng+lat+ita" bit from the cmd-window line.
I got the idea that this is possible from an explanation of the "For" command, which states that "do command" can be followed by "CommandLineOptions" (i.e., "-l eng+lat+ita").
Any help would be much appreciated... 'cause I've been banging my head on this one for hours now...
UPDATE: Found an alternative, but still would like an answer to my question.
I didn't know that "FOR" commands could be run from cmd. So, I pasted the folllowing line in the cmd window:
for %i in (*.tif) do "D:\temp\Tesseract-OCR\tesseract.exe" -l eng+lat+ita "%i" "D:\temp\%~ni"
And, it worked!
As I say, though, how to do this with a .bat file?
#ECHO OFF
SETLOCAL
:Start
#Echo off
ECHO.
ECHO This is a batch file
ECHO.
PAUSE
BREAK=ON
Set "_SourcePath=D:\temp\TIFs\*.tif"
Set "_OutputPath=D:\temp\TIFs"
Set "_Tesseract=D:\temp\Tesseract-OCR\tesseract.exe"
:Convert
For %%A in ("%_SourcePath%") Do Echo Converting "%%A"...... &"%_Tesseract%" -l eng+lat+ita "%%A" "%_OutputPath%\%%~nA"
PAUSE
:End
rem Set "_SourcePath="
rem Set "_OutputPath="
rem Set "_Tesseract="
GOTO :EOF
Since I don't have the tesseract utility, I used another. The above worked for me as I expected with that other utility, so no guarantees with tesseract.
It's normal practice to start a batch with setlocal which makes the clean-up effort unnecessary (hence remmed-out) since an implicit endlocal is executed when the batch terminates, restoring the environment to its initial state.
Assigning values containing quotes is valid but awkward when combining elements. Ditto terminating a value with a backslash. I've converted your code to my preferred syntax. Note that the syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned.
Will it work in your situation? Over to you to try.

Why does this batch file close immediately when called from a shortcut, despite it working correctly when called from command line?

Edit 3 (SOLUTION):
As michael_heath described in his answer, the issue came down to two things: how exactly windows builds commands when executing something through a shortcut, and the very specific (and frankly ridiculous) consequences of the \C switch on cmd.exe. For future reference, if any other poor soul stumbles into this StackOverflow question, the problem was fixed by changing the "Target" property in the shortcut to a slightly edited version of Michael's answer, specifically C:\Windows\System32\cmd.exe /C #"C:\{path-to-script}\link.bat". Here's a screenshot too, if necessary, although you unfortunately can't see the whole Target line.
Huge thanks again to Michael.
I am attempting to make a personal batch utility to create a symlink on the desktop, much in the same way "Send to... > Desktop" works with shortcuts. I use symbolic links frequently to allow things like my bash configuration files (.bashrc and .bash_profile, etc) to be version controlled elsewhere for portability, and for several other things on my computer.
For ease of use, my idea was to create a simple batch file to do this for me, and place the symlink on the desktop. Then, I would put a shortcut to this file in the Send To folder so it appears in Send To in the context menu (I am aware that mklink requires admin privileges, so the shortcut is set to run as administrator also).
The following is the file I have written:
#echo off
set f=%~1
set switch=
if exist "%f%\*" set switch=/D
for /F "delims=" %%i in ("%f%") do set name=%%~nxi
mklink %switch% "%USERPROFILE%\Desktop\%name%" "%f%"
if not %ERRORLEVEL%==0 pause
Here is the general idea of what I'm trying to do:
Strip the quotes on the input, if any (%~1)
Check if the input is a directory
Get the base name and file extension of the input (%%~nxi)
Make the link
If an error occurred, pause so it can be seen rather than exiting (because the batch file is called from the shortcut)
It works perfectly fine until I give it an input that contains spaces in the name of the file or directory. I actually haven't tested what happens if there is a directory with a space in the path, but not in the base name of the actual file or directory, but I assume the same problem will be present.
I have made several changes to attempt to get it to work with files with spaces, including stripping the quotes on the input in that first line so that the quotes aren't doubled later, and that "delims=" thing on the for loop. Those two solutions I found here, actually.
But despite my best efforts, no matter what I do, the file closes immediately when given an input with a space. I have littered every line with pauses, run the script from the command line with a manually entered input so it would not exit, and run each individual command (where possible) from the command line.
Infuriatingly, when I run it from the command line or run the individual commands, it all works perfectly even with spaces in the input. I even created another batch file that does nothing but output the input it receives and ran that from Send To, and confirmed that the input is the same as I entered from the command line.
What on Earth is going wrong then when called from that shortcut in Send To?
Edit 1: The properties of the shortcut itself are as follows:
Target: C:\Users{username}\vc\git\util-scripts\bat\link.bat
Start in: C:\Users{username}\vc\git\util-scripts\bat
Here is a screenshot as well:
Because I just made my account here I can't embed the picture but here it is
Edit 2: This is the current code I am using, as suggested by Gerhard Barnard, however the problem still persists:
#echo off
set "fname=%~1"
set switch=
if exist "%fname%\.*" set "switch=/D"
for /F "delims=" %%i in ("%fname%") do (
mklink %switch% "%USERPROFILE%\Desktop\%%~nxi" "%fname%"
if errorlevel 1 pause
)
#echo off
setlocal
rem Set the path for the created symlink.
set "linkdir=%USERPROFILE%\Desktop"
for %%A in (%*) do call :link "%%~A"
rem Check results.
echo: & dir /A:L "%linkdir%" & pause
exit /b
:link
set "switch="
if exist "%~1\*" set "switch=/D"
for /F "delims=" %%A in ("%~1") do set "name=%%~nxA"
if not defined name echo Variable "name" not defined.& exit /b 1
mklink %switch% "%linkdir%\%name%" "%~1"
exit /b 0
Your batch-file code is working.
This code does multiple file or folders.
This code also helped to test all at once,
files, folders, symlinked files and symlinked
folders as targets.
If you only want 1 target to be processed,
then just change the %* to "%~1".
The main issue is the command string in the shortcut.
C:\Users\{username}\vc\git\util-scripts\bat\link.bat
The file type of .bat is going to build a command such as:
C:\Windows\System32\cmd.exe /C "C:\Users\{username}\vc\git\util-scripts\bat\link.bat" %*
%* is substituted with the passed arguments.
If you have the command with an argument with double quotes,
it may look like:
C:\Windows\System32\cmd.exe /C "C:\Users\{username}\vc\git\util-scripts\bat\link.bat" "C:\Users\a file.txt"
The command string after /C has 4 double quotes
and double quotes are at both ends.
The behavior changes due to the double quotes.
A quote from cmd /?:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
In section 1, "no /S switch" is true, then the next is
"exactly two quote characters" which is false.
This now applies section 2, which can make the
command string after /C with stripped double quotes:
C:\Users\{username}\vc\git\util-scripts\bat\link.bat" "C:\Users\a file.txt
The space is quoted though the rest is exposed,
which is an invalid command string in this case.
Note that C:\Users\a file.txt is an example
passed argument that was double quoted as
"C:\Users\a file.txt".
A change in the command string in the shortcut to:
C:\Windows\System32\cmd.exe /C echo: & "C:\Users\{username}\vc\git\util-scripts\bat\link.cmd"
The command is now C:\Windows\System32\cmd.exe which
gives some more control with the command string.
After the /C, echo: is used to avoid the command
string beginning with a double quote, which helps to
prevent double quotes being stripped at both ends because
the command string no longer starts with a double quote.
After the & is the command that is important and will
now work even if the arguments end with a double quote.
You can replace the echo: & with another initial command.
You can also use # before the command string, so the shortcut
command string would be:
C:\Windows\System32\cmd.exe /C #"C:\Users\{username}\vc\git\util-scripts\bat\link.cmd"
So whatever works the best for your use case.
Try without the /F option which is not needed here, we also do not need to set a variable as it will work perfectly fine with the expanded meta variable:
#echo off
set "fname=%~1"
set switch=
if exist "%fname%\.*" set "switch=/D"
for %%i in ("%fname%") do (
echo mklink %switch% "%USERPROFILE%\Desktop\%%~nxi" "%fname%"
if errorlevel 1 pause
)

Getting notification from xcopy if file copy

I am generating a Windows Batch script to copy a file, only when the source is updated. If the file is updated, I want to delete another file.
The problem is that I can't find a simple way to trigger an event when the file update happens.
I thought of using %ERRORLEVEL% but this gives 0 whether file is copied or not.
I also thought of saving the xcopy output to a text file and then processing the file but this just seems to a little impractical for such a simple task?
Any other Ideas?
Code so far
SET SOURCEFILE=%CD%\source.txt
SET DELFILE=%CD%\toDelete.txt
SET DESTDIR=%WINDIR%\Deployment\
xcopy "%SOURCEFILE%" "%DESTDIR%" /c /d /q /y
REM IF File is updated, delete %DELFILE%
I explain the method used in command line posted by Aacini on entire batch code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFile=source.txt"
set "DeleteFile=toDelete.txt"
set "DestinationDirectory=%SystemRoot%\Deployment\"
for /F %%I in ('%SystemRoot%\System32\xcopy.exe "%SourceFile%" "%DestinationDirectory%" /C /D /Q /Y 2^>nul') do set "CopiedFilesCount=%%I"
if %CopiedFilesCount% GTR 0 del "%DeleteFile%"
rem Add here more command lines using one of the 3 environment variables define above.
endlocal
First it is very important on copying a single file with XCOPY that the destination directory path ends with a backslash as otherwise XCOPY would prompt if the destination is a directory or a file.
XCOPY as used here always outputs to handle STDOUT as last line an information message with the number of files being copied at beginning even when nothing is copied or when an error occurred.
The command FOR executing XCOPY in a separate command process in background captures this output to handle STDOUT and processes it line by line.
Empty lines and lines starting with a semicolon are ignored with using the default options as used here with no eol= option. The other lines are processed with splitting each line up into strings separated by spaces or horizontal tabs on using default delimiters as used here because of no delims= option. Because of not using tokens= option just the first space/tab separated string of each line is assigned to loop variable I and the rest of the line is ignored.
The current value of the loop variable I is assigned on each processed line to environment variable CopiedFilesCount replacing its previous value.
The first space/tab separated string on last line output by XCOPY is the number of copied files which is here on copying just a single file either 0 or 1. So finally after FOR loop execution finished the environment variable CopiedFilesCount has either 0 or 1 as value.
The value is compared with GREATER THAN operator of command IF to determine if the file was copied in which case the other file is deleted.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
for /?
if /?
rem /?
set /?
setlocal /?

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

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
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!
%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…
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.
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
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.
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':
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;
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?
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)
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.
#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
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 uses cmd /c under the hood
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
(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 called 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 called 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.

Detecting how a batch file was executed

Assuming Windows, is there a way I can detect from within a batch file if it was launched from an open command prompt or by double-clicking? I'd like to add a pause to the end of the batch process if and only if it was double clicked, so that the window doesn't just disappear along with any useful output it may have produced.
Any clever ways to do this? I'm looking for solutions I could rely on to work on a machine that was configured more or less with default settings.
I just ran a quick test and noticed the following, which may help you:
When run from an open command prompt, the %0 variable does not have double quotes around the path. If the script resides in the current directory, the path isn't even given, just the batch file name.
When run from explorer, the %0 variable is always enclosed in double quotes and includes the full path to the batch file.
This script will not pause if run from the command console, but will if double-clicked in Explorer:
#echo off
setlocal enableextensions
set SCRIPT=%0
set DQUOTE="
#echo do something...
#echo %SCRIPT:~0,1% | findstr /l %DQUOTE% > NUL
if %ERRORLEVEL% EQU 0 set PAUSE_ON_CLOSE=1
:EXIT
if defined PAUSE_ON_CLOSE pause
EDIT:
There was also some weird behavior when running from Explorer that I can't explain. Originally, rather than
#echo %SCRIPT:~0,1% | findstr /l %DQUOTE% > NUL
if %ERRORLEVEL% EQU 0 set PAUSE_ON_CLOSE=1
I tried using just an if:
if %SCRIPT:0,1% == ^" set PAUSE_ON_CLOSE=1
This would work when running from an open command prompt, but when run from Explorer it would complain that the if statement wasn't correct.
Yes. Patrick Cuff's final example almost worked, but you need to add one extra escape, '^', to make it work in all cases. This works great for me:
set zero=%0
if [^%zero:~0,1%] == [^"] pause
However, if the name of the batch file contains a space, it'll be double quoted in either case, so this solution won't work.
Don't overlook the solution of having two batch files:
abatfile.bat and abatfile-with-pause.bat
The second simply calling the first and adding a pause
Here's what I use :
rem if double clicked it will pause
for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" pause
I use a parameter "automode" when I run my batch files from scripts.
set automode=%7
(Here automode is the seventh parameter given.)
Some code follows and when the file should pause, I do this:
if #%automode%==# pause
One easy way to do it is described here:
http://steve-jansen.github.io/guides/windows-batch-scripting/part-10-advanced-tricks.html
There is little typo in the code mentioned in the link. Here is correct code:
#ECHO OFF
SET interactive=0
ECHO %CMDCMDLINE% | FINDSTR /L /I %COMSPEC% >NUL 2>&1
IF %ERRORLEVEL%==0 SET interactive=1
ECHO do work
IF "%interactive%"==1 PAUSE
EXIT /B 0
Similar to a second batch file you could also pause if a certain parameter is not given (called via clicking).
This would mean only one batch file but having to specify a -nopause parameter or something like that when calling from the console.
crazy idea: use tasklist and parse it's results.
I've wrote in a test batch file:
tasklist > test.out
and when I double-clicked it, there was an additional "cmd.exe" process just before the tasklist process, that wasn't there when the script was run from command line (but note that might not be enough if someone opens a command line shell and then double-click the batch file)
Just add pause regardless of how it was opened? If it was opened from command prompt no harm done apart from a harmless pause. (Not a solution but just thinking whether a pause would be so harmful / annoying )

Resources