How do I emulate a "wrapper script" on Windows? - windows

On Linux, when I want to prepare the environment of a program before starting it, I'm using a wrapper script:
export JAVA_HOME=...
cd /some/folder
exec ./tool "$#"
How would I do the last line, especially the "$#", on Windows?
Note: I'm wrapping commands which take a lot of arguments (like java or mvn), so I need a solution which works for > 10 arguments.
Being able to exec would be nice but is only a minor concern.

Probably something like:
#echo off
setlocal enableextensions
set JAVA_HOME=...
cd ...
start "" .\sometool %*
endlocal
Setlocal localizes environment changes to the script (see setlocal /? for details), and %* means 'all script parameters'. The start command is a cmd.exe command that spawns an executable.
The start command has odd parsing rules; the first quoted string on its command line is considered to be a console window title, which is superfluous if you are not spawning a console window. This means that a command like this won't work as expected:
start "C:\Program Files (x86)\Microsoft Office\Office14\excel.exe"
If you run this command, you will spawn a new instance of cmd.exe with the quoted string as its console window title, which is clearly not what was intended. Instead, you have to write this:
start "" "C:\Program Files (x86)\Microsoft Office\Office14\excel.exe"

Related

How to set an env variable with multiline file content in windows command prompt

I have a file say my-file.dat which has multiple lines. I want to set an env variable say MYVAR that will contain the content of my-file.dat.
That is, in windows command prompt, the output of type my-file.dat be same as the output of echo %MYVAR% and with new-line preserved.
In RHEL/MAC, it is typically done like this export MYVAR=$(cat my-file.dat), but how do I do the similar in windows command prompt (not really interested in powershell, but feel free to share examples it might be my backup option)
Following the answer of this Stackoverflow question Multiline text file, how to put into an environment variable I could get a variable to hold the content of my-file.dat. But this variable's scope seems to be the batch file. Even though I run the batch file from the command prompt, I don't see the batch-file's variable is available in the command prompt.
I tried set /P MYVAR=<my-file.dat , but this sets only the first line whereas I want all lines when I echo MYVAR
Pls help.
The technique you use requires delayed expansion, which is not enabled by default. So the code issues setlocal enableDelayedExpansion. But that localizes environment changes. When the script ends there is an implicit endlocal, and the environment is restored to what existed before the setlocal.
The simplest solution is to run the script in a session where delayed expansion is already enabled so that you can remove setlocal enableDelayedExpansion. You can do this simply by running
cmd /v:on from your command line before executing your script.
There is another simple, but ugly option. The implicit endlocal does not occur if your script has a fatal syntax error (I consider this to be a bug in cmd.exe). So you can put the following at the end of your script:
:: Your current script goes here.
:: I'm assuming your script falls through to the end and does not use EXIT /B
call :fatalErr 2>nul
:fatalErr
if
But I discourage you from using this technique if you might be executing your script multiple times - your dead environments will begin to pile up.
Also - please remember that variables are limited to ~8191 characters - your script will fail if the file you are trying to capture exceeds the limit. This is a hard limit of cmd.exe
Update
You could put the cmd /v:on command within your script if you add the /K option. The IF statement tests if delayed expansion is enabled or not. If not, then it reruns the script via cmd.exe with the /K option and /V:ON.
#echo off
if "!!" neq "" cmd /v:on /k "%~f0"
:: rest of your script goes here.

startup batch file hangs up on second command

I created a startup bat file that looks like this
taskkill /im RemoteDesktopManager.exe
C:\Users\kheradmand\AppData\Local\Google\Chrome\Application\chrome.exe
"C:\Program Files (x86)\JetBrains\PhpStorm 7.1.2\bin\PhpStorm.exe"
"C:\Program Files\Mozilla Firefox\firefox.exe"
it does the first and second, but won't go any further, they all exist
how can I fix this?
update : I tried suggestion provided by #phd443322 and wrote this:
taskkill /im RemoteDesktopManager.exe
start "" /w C:\Users\kheradmand\AppData\Local\Google\Chrome\Application\chrome.exe
start "" /w "C:\Program Files (x86)\JetBrains\PhpStorm 7.1.2\bin\PhpStorm.exe"
start "" /w "C:\Program Files\Mozilla Firefox\firefox.exe"
intrestingly each command still waits for that program to be closed to continue to the next.
so why still not working?
Below there is a working Batch file, as first advised by phd443322:
taskkill /im RemoteDesktopManager.exe
start "" C:\Users\kheradmand\AppData\Local\Google\Chrome\Application\chrome.exe
start "" "C:\Program Files (x86)\JetBrains\PhpStorm 7.1.2\bin\PhpStorm.exe"
start "" "C:\Program Files\Mozilla Firefox\firefox.exe"
Batch files wait for programs to exit unlike interactive. These are the rules documented in the Start command.
If Command Extensions are enabled, external command invocation
through the command line or the START command changes as follows:
non-executable files may be invoked through their file association just
by typing the name of the file as a command. (e.g. WORD.DOC would
launch the application associated with the .DOC file extension).
See the ASSOC and FTYPE commands for how to create these
associations from within a command script.
When executing an application that is a 32-bit GUI application, CMD.EXE
does not wait for the application to terminate before returning to
the command prompt. This new behavior does NOT occur if executing
within a command script.
When executing a command line whose first token is the string "CMD "
without an extension or path qualifier, then "CMD" is replaced with
the value of the COMSPEC variable. This prevents picking up CMD.EXE
from the current directory.
When executing a command line whose first token does NOT contain an
extension, then CMD.EXE uses the value of the PATHEXT
environment variable to determine which extensions to look for
and in what order. The default value for the PATHEXT variable
is:
.COM;.EXE;.BAT;.CMD
Notice the syntax is the same as the PATH variable, with
semicolons separating the different elements.
When searching for an executable, if there is no match on any extension,
then looks to see if the name matches a directory name. If it does, the
START command launches the Explorer on that path. If done from the
command line, it is the equivalent to doing a CD /D to that path.

Environment Variable not expanding

Platform: Windows Vista Service Pack 2 (x86)
I was messing around with batch scripts and realized that they could act as the command prompt(yes I know batch scripts run threw the command prompt) I mean that a batch script could prompt the user for a command and then call the command.
SET command=
SET /P command=%cd%^>
ECHO(
%command%
ECHO(
The only problem is that when I type in for example cd %windir% I get an error message telling me that the system cannot find the path specified. So I typed echo %windir% and echo printed %windir% exactly it wasn't expanded at all. I am wondering if the problem is because I have the environment variable nested inside the %command% variable but from what I understand CMD.exe does support nested environment variables. I tried using Delayed Expansion but the variable still didn't expand.
Add a call or cmd /c to evaluate variables that way.
#echo off
setlocal
SET /P command=%cd%^>
call %command%
ECHO;

Is there an equivalent source command in Windows CMD as in bash or tcsh?

I know that in the unix world, if you edit your .profile or .cshrc file, you can do a source ~/.profile or source ~/.cshrc to get the effect on your current session. If I changed something in the system variable on Windows, how can I have it effect the current command prompt session without exiting the command prompt session and opening another command prompt session?
In the usual Windows command prompt (i.e. cmd.exe), just using call mybat.bat did what I wanted. I got all the environment variables it had set.
The dos shell will support .bat files containing just assignments to variables that, when executed, will create the variables in the current environment.
c:> type EnvSetTest.bat
set TESTXYZ=XYZ
c:> .\EnvSetTest.bat
c:> set | find "TESTX"
TESTXYZ=XYZ
c:>
IHTH.
Following example will help you to solve your problem.
env.bat This file is for setting variables. Its contents are given blow.
set name="test3"
test.bat Our main batch file.
call env.bat
call print.bat
pause
Now print.bat batch file to print variables. Its contents given below
echo %name%
I am afraid not, but you can start using Powershell, which does support dot sourcing. Since powershell window is really based on cmd so all your dos command will continue to work, and you gain new power, much more power.
The only way I have found this to work is to launch a new cmd window from my own config window. eg:
#echo off
echo Loading...
setlocal enabledelayedexpansion
call 1.cmd
call 2.bat
...
...
if "%LocalAppData%"=="" set LocalAppData=%UserProfile%\Local Settings\Application Data
SET BLAHNAME=FILE:%LocalAppData%\BLAH
call blah blah
cmd
The last cmd will launch a new cmd prompt with the desired settings exported to the command window.
Here's a workaround for some limited use-cases. You can read-in a file of commands and execute them in-line. For example the calling command file looks like:
echo OFF
SETLOCAL ENABLEDELAYEDEXPANSION
:
echo. ----------------
echo. set-up java
echo. ----------------
echo.
rem call %DEV_SCRIPTS%\setup-java
for /F "tokens=*" %%A in ( %DEV_SCRIPTS%\setup-java.bat ) do (
%%A
)
call %DEV_SCRIPTS%\show-java
:
In the setup-java.bat file you can't use % expansion. You need to use !; e.g.:
set JRE_HOME=!JRE_08!
rem
set JRE_TARGET=!JRE_HOME!
So you are litterally source-ing commands from a text file. You will need to test which commands sourced in this way. It took a few trials just to set some environment variables.
I don't think we can do logic or loops because the command processor scans the file at the start. I am OK just having a simple workaround to reuse shared things like environment definitions. Most other things won't need an actual source command (I am hoping). Good luck.
For example to set VC# vars
C:\Windows\System32\cmd.exe /k "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
Use git bash for windows, it works totally fine!

Pausing a batch file when double-clicked but not when run from a console window?

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?
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.
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.
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
The variable "testl" gets the full line of the cmd processor call, 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 (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
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
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.

Resources