Please Please Please
can anyone explain why the following code works if I manually enter it line by line but it doesn't work if I try to execute it through a batch file?
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SETLOCAL EnableExtensions
Set Source=%computername%
Set Backups=%Source%\c$\users\travel\desktop
Set Target=dan-2813-pc
Set Action=Restore
IF EXIST "\\%Backups%\%Source%-OrgUnit.txt" (
SET /p OrgUnit=<\\%Backups%\%Source%-OrgUnit.txt
SET /p MoveOU=At the end of the %Action%, do you want to move %Target% to %OrgUnit% [Y/N]?
)
ENDLOCAL
I'm at a complete loss for what I'm missing here.
The help for ENABLEDELAYEDEXPANSION says:
ENABLEDELAYEDEXPANSION / DISABLEDELAYEDEXPANSION
enable or disable delayed environment variable
expansion. These arguments takes precedence over the CMD
/V:ON or /V:OFF switches. See CMD /? for details.
And the help for /V: says:
/V:ON Enable delayed environment variable expansion using ! as the
delimiter. For example, /V:ON would allow !var! to expand the
variable var at execution time. The var syntax expands variables
at input time, which is quite a different thing when inside of a FOR
loop.
In other words, if you want to see the changed value of a enviornment variable after setting it within a block, you need to change your code to use ! instead of %:
SET /p MoveOU=At the end of the %Action%, do you want to move %Target% to !OrgUnit! [Y/N]?
Related
I'm trying to use CMDER for a development environment that I've setup.
Basically I've created a .bat file that calls:
#ECHO OFF
start Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\Cmder.exe
Then I've placed the file startdev.bat in:
%CMDER_HOME%\config\profile.d
So everything seems to work just fine, but when the startdev.bat finishes, issuing an:
echo %PATH%
returns:
Z:\_DEV\OS_WINDOWS\1_COMPILER\JDK\ORACLE\1.8.0_181\bin;Z:\_DEV\OS_CYGWIN\bin;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CLutils;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\PUTTY;Z:\_DEV\OS_WINDOWS\6_VERSION_CONTROL\PortableGit\bin;C:\WINDOWS;C:\WINDOWS\SysWOW64;C:\WINDOWS\System32
...any idea what's happening?
I would either expect CMDER to override PATH with the value from its own settings, or use my full path, which before the startdev.bat ends shows the value of:
PATH=Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\vendor\conemu-maximus5;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\vendor\conemu-maximus5\ConEmu;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\vendor\conemu-maximus5\ConEmu\Scripts;Z:\_DEV\OS_ALL\JVM\3_BUILD_TOOLS\GRADLE\5.4\bin;Z:\_DEV\OS_ALL\JVM\3_BUILD_TOOLS\MAVEN\3.5.4\bin;Z:\_DEV\OS_ALL\JVM\3_BUILD_TOOLS\ANT\1.10.5\bin;Z:\_DEV\OS_WINDOWS\3_BUILD_TOOLS\NODE\LTS\10.15.3;Z:\_DEV\OS_WINDOWS\3_BUILD_TOOLS\NODE\LTS\10.15.3\node_modules;Z:\_DEV\OS_WINDOWS\1_COMPILER\GO\1.12.4\bin;Z:\_DEV\OS_WINDOWS\1_COMPILER\PYTHON\32bit\2.7.13;Z:\_DEV\OS_WINDOWS\1_COMPILER\PYTHON\32bit\2.7.13\scripts;Z:\_DEV\OS_WINDOWS\1_COMPILER\ANDROID\android-sdk-windows\platform-tools;Z:\_DEV\OS_WINDOWS\1_COMPILER\JDK\ORACLE\1.8.0_181\bin;Z:\_DEV\OS_CYGWIN\bin;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CLutils;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\PUTTY;Z:\_DEV\OS_WINDOWS\6_VERSION_CONTROL\PortableGit\bin;C:\WINDOWS;C:\WINDOWS\SysWOW64;C:\WINDOWS\System32
..but the fact that it only seems to be keeping the value as defined about halfway through the batch job is strange.
Any ideas?
First I recommend opening a command prompt window and run setlocal /? and endlocal /? to get displayed the help/documentation for those two commands. Very important to know is that every setlocal without a corresponding endlocal results in an implicit execution of endlocal by cmd.exe before exiting processing of a batch file or a subroutine called with command CALL.
Next I suggest reading this answer for even more details about the commands SETLOCAL and ENDLOCAL and what happens on using them.
I suggest like michael_heath to change this code block:
setLocal EnableDelayedExpansion
set CLASSPATH=.
for /R %JRE_HOME%\lib %%a in (*.jar) do (
set CLASSPATH=!CLASSPATH!;%%a
)
set CLASSPATH=!CLASSPATH!
Better would be:
setLocal EnableExtensions EnableDelayedExpansion
set CLASSPATH=.
for /R "%JRE_HOME%\lib" %%a in (*.jar) do set "CLASSPATH=!CLASSPATH!;%%a"
endlocal & set "CLASSPATH=%CLASSPATH%"
Now the local environment is ended with passing the environment variable CLASSPATH from local environment, on which it was defined, to the restored previous environment because of cmd.exe expands %CLASSPATH% to current value of the environment variable CLASSPATH in current local environment before executing the command endlocal which restores the previous environment.
Wrong in your batch file is also set WINDIR=%SystemRoot%;%SystemRoot% which should be set "WINDIR=%SystemRoot%".
I recommend further reading Why is no string output with 'echo %var%' after using 'set var = text' on command line? It explains why the syntax set "variable=string value" is recommended nowadays. Many of the environment variable definitions use directly or indirectly %UserProfile% which means depending on whatever the user currently running the batch file has entered as user name on creation of the user account. I have seen users entering their name containing a space and non ASCII characters. And I have seen users creating an account with a user name containing character & like Company GmbH & Co. An ampersand outside a double quoted argument string is interpreted as AND operator and cmd.exe tries to execute after set also the remaining string after & as command line on using something like set USERHOME=%DEVHOME%\%USERNAME% instead of set "USERHOME=%DEVHOME%\%USERNAME%". Well, startdev.bat redefines nearly all predefined Windows Environment Variables including USERNAME and USERPROFILE and so is written safe for most environment variable definitions.
This code block is also not optimal:
FOR /F "usebackq" %%i IN (`hostname`) DO SET HOSTNAME=%%i
echo Running on hostname: %HOSTNAME%
The host name respectively computer name could contain also a space or characters critical for command line or start with a semicolon for some unknown reason. So better would be:
FOR /F delims^=^ eol^= %%i IN ('hostname') DO SET "HOSTNAME=%%i"
setlocal EnableDelayedExpansion & echo Running on host name: !HOSTNAME!& endlocal
Whereby there is the environment variable COMPUTERNAME predefined by Windows making it possible to use just following command line:
setlocal EnableDelayedExpansion & echo Running on host name: !ComputerName!& endlocal
An ECHO command line containing an immediately expanded environment variable reference on which it is unknown if its value contains &|<> is always a problem because of the environment variable reference is expanded before further processing of the command line by cmd.exe as described at How does the Windows Command Interpreter (CMD.EXE) parse scripts?
I suggest also reading DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ and avoid the usage of echo. in the batch file to output an empty line.
"halfway through the batch job" as you have a
setLocal EnableDelayedExpansion which sets any further
changes to the variable PATH or other set variables as local.
The endLocal not specified is implied at the end of the script.
To resolve this, use endLocal and set CLASSPATH=%CLASSPATH%
on the same parsed line to set CLASSPATH as global.
Change this part:
setLocal EnableDelayedExpansion
set CLASSPATH=.
for /R %JRE_HOME%\lib %%a in (*.jar) do (
set CLASSPATH=!CLASSPATH!;%%a
)
set CLASSPATH=!CLASSPATH!
to this:
setLocal EnableDelayedExpansion
set CLASSPATH=.
for /R %JRE_HOME%\lib %%a in (*.jar) do (
set CLASSPATH=!CLASSPATH!;%%a
)
endLocal & set CLASSPATH=%CLASSPATH%
After that changed part, the script will set variables as global again.
I would like to create a batch script which allows to create number and name of folder chosen by the user.
However, I received a syntax error using the script below.
variable "nome" is not taken.
Here is my code:
echo How many folders?
set /p cc=tell me how many
SETLOCAL EnableDelayedExpansion
FOR /L %%G IN (1,1,%cc%) DO (set /p nome=tell me the name
md %nome%)
pause
mr xyz, please use the search bar to search for delayed expansion. It's not that hard.
What Is DelayedExpansion
Batch-file variables are expanding in the moment the line is parsed. That means the nome variable isn't set when the entire for loop is parsed.
How-To Make The Variable Expand At Run-time?
SETLOCAL Method
Add
setlocal enableDelayedExpansion
anywhere before the for loop, so cmd will process the variable at run-time. And change %nome% to !nome!.
CALL MKDIR/MD Method
Change your MD statement to:
call MD %%nome%%
As this will trigger the emulated delayed expansion using the special property of call and %%.
I just found out that if you do the following:
set Variable=Test & echo %Variable% --Outputs "%Variable%"
echo %Variable% --Outputs "Test"
The change won't take effect until a new line runs. I need to have it take effect immediately as I need to use it with a very long, one-lined command.
You need delayed expansion or call echo:
#echo off
setlocal enableDelayedExpansion
set var=val&echo !var!
endlocal
set var=val&call echo %%var%%
If you have compositions of commands put together with & or in brackets the set command will take effect after all of them are executed.So you need or delayed expansion (which will allow you to access the variables with ! instead of %) or call
To enable the delayed expansion in command prompt you need to start like this cmd /v:on :
>cmd /v:on
>set Variable=Test & echo !Variable!
I want to get dir=%dir:~-here% a var.
I find out that this dir=%dir:~-%var%% unfortunaly this doesn`t work.
then I tried :
set var=2
echo dir=%%dir:~-%var%%% > file.txt
for /f "tokens=* delims=" %%a in (file.txt) do set dir=%%a
but then is dir for real %dir:~-2%. If anybody understands my, am I asking you is there a way to do it??
THNX
#echo off
setlocal enabledelayedexpansion
set "var=-2"
echo !cd:~%var%!
To use a variable inside a variable substring operation, the easiest way is to use delayed expansion
If you want to expand variables in a line two times, you need to use Delayed Expansion:
setlocal EnableDelayedExpansion
set var=2
echo dir=!dir:~-%var%! > file.txt
The first expansion happen at %var%, the second (delayed) expansion happen at !dir:~-2!.
EDIT: Another possible way is use the call command that causes that the line be parsed again:
set var=2
call echo dir=%%dir:~-%var%%% > file.txt
When the line is parsed the first time, the first expansion is performed:
call echo dir=%dir:~-2% > file.txt
The call command causes that the line be parsed again and get the final result.
Here is another way to do it with your example.
Using call this way causes an issue with ^ characters and is relatively slower than delayed expansion.
#echo off
set dir=aaabbbccc
set var=3
>file.txt call echo dir=%%dir:~-%var%%%
pause
How do you use setlocal in a batch file? I am just learning scripting and would like it explained to me in very simple terms.
I have a script that stops and says < was unexpected at this time it may have something to do with not having any setlocal statements in the script.
You make the first line SETLOCAL. This example is from the linked article below:
rem *******Begin Comment**************
rem This program starts the superapp batch program on the network,
rem directs the output to a file, and displays the file
rem in Notepad.
rem *******End Comment**************
#echo off
setlocal
path=g:\programs\superapp;%path%
call superapp>c:\superapp.out
endlocal
start notepad c:\superapp.out
The most frequent use of SETLOCAL is to turn on command extensions and allow delayed expansion of variables:
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
For more info on SETLOCAL see the Command Line Reference at Microsoft TechNet.
Direct link to Setlocal
Suppose this code:
If "%getOption%" equ "yes" (
set /P option=Enter option:
echo Option read: %option%
)
Previous code will NOT work becase %option% value is replaced just one time when the IF command is parsed (before it is executed). You need to "delay" variable value expansion until SET /P command had modified variable value:
setlocal EnableDelayedExpansion
If "%getOption%" equ "yes" (
set /P option=Enter option:
echo Option read: !option!
)
Check this:
set var=Before
set var=After & echo Normal: %var% Delayed: !var!
Guess what the output is...
Try this:
SET PATH=%PATH%;%~dp0;
This will get your local folder your are running the batch from and add it to the current path.
example: if your are running a .bat or .cmd from d:\tools\mybatch.bat
it will add d:\tools to the current path so that it may find additional files on that folder.