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!
Related
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]?
I'm new to batch and I'm trying to make a speed/distance/time calculator. The code works fine until I try to echo the total. Here's my code:
#ECHO off
COLOR 0f
TITLE Speed Distance Time Calculator
:BEGIN
SET /P type="Calculate speed/distance/time? (S/D/T): "
CLS
IF /I "%type%"=="s" (
SET /P distance="Distance: "
CLS
SET /P dUnits="Distance units (mile/m/km):"
CLS
SET /P time="Time: "
CLS
SET /P tUnits="Time units (h/s):"
CLS
SET total=%distance%/%time%
ECHO %total%
)
It outputs:
ECHO is off
I've looked around for answers and have tried "enabledelayedexpansion" but it did not work.
To do division (or any arithmetic operation) in a batch file using the SET command, you have to specify the /A switch. Additionally, you'll need to turn on delayed variable expansion, since you will be dynamically changing variables in the batch file, and then using them.
When using delayed expansion variables you must reference them with ! instead of %. The exclamation marks tell the command processor that you want that particular variable's expansion to be delayed. Any variables that use percentage signs will be expanded at initial parse time.
So at the top of your batch file, under the #ECHO off, turn on delayed expansion:
SETLOCAL EnableDelayedExpansion
Then perform the calculation like so:
SET /A total=!distance!/!time!
ECHO !total!
I have a batch file with the following header:
#Echo off
SETLOCAL EnableDelayedExpansion EnableExtensions
Within a If statement, enclosed in parenthesis (), I have the following code:
Echo SOME_VAR|FindStr /r /C:"^.*SOME.*$"
Echo Error: !errorlevel!
Echo %%SOME_VAR%%|FindStr /r /C:"^.*SOME.*$"
Echo Error: !errorlevel!
This will print:
SOME_VAR
Error: 0
Error: 1
If SOME_VAR is an existing environment variable, this is what I get. If I delete the variable, I get the expected success.
What happens here? Do I need to escape something more? How can I get a successful find on the 2nd one if the variable exists? I'm only interested in doing a text search where the searched text contains the % character and happens to match an existing variable name.
By the way, the source for the comparison will eventually be a variable too, in which I've loaded the PATH as read from the Windows Registry. So eventually, the string I am searching for will become /C:"^.%%SOME_VAR%%;.*$"
My PATH variable looks like this:
%SOME_VAR%;C:\Windows\system32...................etc
Yes, there is another layer of escape required because each side of the pipe is executed via CMD /C with a command line context, not a batch context. The initial batch parser transforms %%SOME_VAR%% to %SOME_VAR%. The command line parser then leaves %SOME_VAR% as is if the variable is undefined. We need to prevent the expansion if the variable is defined. Doubling the percents does not work in a command line context. The solution is to insert a disappearing caret somewhere between the percents, like %^SOME_VAR%. The caret is treated as part of the variable name, so it prevents expansion of the variable (unless you have a variable named ^SOME_VAR). After failed expansion, the caret is consumed by the normal escape process. The caret must be escaped so that the batch parser passes the caret to the CMD /C command line context.
The final batch line becomes:
Echo %%^^SOME_VAR%% | FindStr SOME_VAR
Note: I simplified the FINDSTR command into a much simpler, but equivalent search.
When you modify the search on the right to include the percents, you will need to insert the escaped caret as well.
Update in response to question in comment
The following code demonstrates some possible ways to work with variables:
#echo off
setlocal disableDelayedExpansion
:: Put both the text you want to search, as well as the search itself, in variables
set "text=%%SOME_VAR%%;C:\Windows\system32...................etc"
set "search=%%SOME_VAR%%"
echo text=%text%
echo search=%search%
echo(
echo(
echo Starting with delayed expansion disabled
echo -----------------------------------------
echo(
:: Use delayed expansion to safely expand any variable without worrying about content.
:: Both sides of the pipe are executed in a command line context with delayed expansion disabled.
:: You must use CMD /V:ON to enable delayed expansion within the pipe.
echo Test when SOME_VAR is undefined:
set "SOME_VAR="
if 1==1 (
cmd /v:on /c echo !text!|cmd /v:on /c findstr "!search!"
)
echo(
echo Test when SOME_VAR is defined:
set "SOME_VAR=DEFINED"
if 1==1 (
cmd /v:on /c echo !text!|cmd /v:on /c findstr "!search!"
)
echo(
setlocal enableDelayedExpansion
echo(
echo(
echo Now try with delayed expansion enabled
echo -----------------------------------------
echo(
:: Even though delayed expansion is enabled within the batch script, it is still disabled
:: within the pipe, so we still have to explicitly enable it via CMD /V:ON.
:: But now we must prevent expansion of the variables while in the batch context.
:: You have two options:
:: 1) Escape the !. The escape syntax changes depending on whether it is inside quotes or not:
echo Escape test:
if 1==1 (
cmd /v:on /c echo ^^!text^^!|cmd /v:on /c findstr "^!search^!"
)
echo(
:: 2) Enclose both sides of the pipe within parentheses (very weird, but it works)
echo Parentheses test:
if 1==1 (
(cmd /v:on /c echo !text!)|(cmd /v:on /c findstr "!search!")
)
--OUTPUT--
text=%SOME_VAR%;C:\Windows\system32...................etc
search=%SOME_VAR%
Starting with delayed expansion disabled
-----------------------------------------
Test when SOME_VAR is undefined:
%SOME_VAR%;C:\Windows\system32...................etc
Test when SOME_VAR is defined:
%SOME_VAR%;C:\Windows\system32...................etc
Now try with delayed expansion enabled
-----------------------------------------
Escape test:
%SOME_VAR%;C:\Windows\system32...................etc
Parentheses test:
%SOME_VAR%;C:\Windows\system32...................etc
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
I'd like to put each of the many properties' file names into variable fileName and echo them out to the command prompt window. But only the last properties file name to be cycled thru is printed out as many times as there are properties files. Is there an easy fix to this problem. I know that ...DO echo %%-nxG can do the same thing but I'd like to save the file name in %%~nxG for future use.
FOR %%G IN (C:\ExecutionSDKTest_10.2.2\*.properties) DO (
set fileName=%%~nxG
echo %fileName%
)
You need to use delayed expansion:
setlocal enabledelayedexpansion
FOR %%G IN (C:\ExecutionSDKTest_10.2.2\*.properties) DO (
set fileName=%%~nxG
echo !fileName!
)
Environment variables in cmd are expanded when a command is parsed – in this case this includes the whole block in parentheses. So %fileName% gets replaced by an empty string because it didn't have a value before the loop ran. Delayed expansion uses ! instead of % and changes variable evaluation so that they are evaluated just before a command is run.
help set has more details about why and when it is necessary. In general, whenever you modify and use a variable within a loop you have to use delayed expansion, but it comes with a few other benefits too.