How to get selected character
for %%A in (controls\vbalSGrid6.ocx) do (
SET TEXT=%A%
SET SUBSTRING=%TEXT:~9%
echo %SUBSTRING%
)
this is giving echo is off but i only need vbalsgrid6.ocx.
The direct way
set "text=controls\vbalscrid6.ocx"
set "substring=%text:~9%"
No need for the for command, unless you are iterating over a set of files or you don't want to use substring operations to get file names
The easy way to get the name and extension of the file
for %%a in (controls\vbalsgrid6.ocx) do set "fileName=%%~nxa"
%%a hold a reference to the file, and %%~nxa is the file name and extension of the referenced file
A direct translation/corrected version of your code (in this case, iterating over the list of files, but not needed)
#echo off
setlocal enableextensions enabledelayedexpansion
for %%a in (controls\*.ocx) do (
set "text=%%a"
set "substring=!text:~9!"
echo !substring!
)
When the batch parser reaches a line/block of code (code inside parenthesis), the full line/block is checked searching the places where a variable will be readed. All this reads are replaced with the value stored in the variable at parse time, before the line/block is executed. That means that if a variable changes its value inside a block, this changed value can not be accessed from inside the same block as the read operation on the variable was previously replaced with the initial value stored inside it.
To handle this case, delayed expansion is used. When delayed expansion is enabled, it is possible to change (where needed) the syntax to read a variable, from %var% to !var!, indicating to the parser that this read operation should be delayed until the command is executed.
The included code will work while there is no ! in the name of the files. As delayed expansion is active, the parser will try to interpret any !, giving non expected results in some cases. It can be handled but sometimes it can be a bit tricky.
#echo off
setlocal enableextensions disabledelayedexpansion
for %%a in (controls\*.ocx) do (
rem Retrieve the initial text. No problem as delayed expansion is disabled
set "text=%%a"
rem Enable delayed expansion to read the value in %text%. And ensure
rem it is disabled at the moment of the assignment to the substring var
setlocal enabledelayedexpansion
set "substring="
for /f "delims=" %%b in ("!text:~9!") do (endlocal & set "substring=%%b")
rem We need delayed expansion enabled to read the changed value
rem If substring is empty, the previous endlocal was not executed and
rem there is no need for a new setlocal
if defined substring setlocal enabledelayedexpansion
echo(substring value=!substring!
endlocal
)
Related
Below is my code and i am not able to print the variable in windows batch file that stores an extracted value from CSV file
#echo off
Set _InputFile=D:\TH_Scripts\InputParamTest.csv
for /F "usebackq tokens=* delims=" %%A in (%_InputFile%) do (
set the_line=%%A
goto process_line
)
:process_line
echo i am here
pause
for /F "usebackq tokens=1,2,3,4,5,6,7 delims=[,]" %%1 in (%the_line%) do (
set hexcode=%%1
set country=%%2
set reg=%%3
set owner=%%4
set callsign=%%5
set planetype=%%6
set model=%%7
set THISLINE=%hexcode%,%country%,%reg%,%owner%,%callsign%,%planetype%,%model%
echo %THISLINE% > %THEOUTPUTFILE%
pause
)
for /F "usebackq tokens=1,2,3,4,5,6,7 delims=[,]" %%1 in (%the_line%) do (
%%number is not supported by batch syntax. %n means "the nth parameter to the procedure".
change %%1 to %%a. The variables assigned are then %%a, %%b etc. to %%g note case is important. %%a can be %%i if you like - the values extracted are then assigned to %%i..%%o
2.
You need to search for innumerable articles on delayed expansion on SO. The value of %var% within a code block (parenthesised series of instructions) will be the value that the variable had when the code block was encountered - not the value as it is varied in the block (the "run-time" value)
To extract the run-time value, you need to first invoke delayedexpansion mode by executing a setlocal enabledelayedexpansion instruction (usually done directly after the initial #echo off) and then access the run-time value of the variable by using !var!.
That having been said, unless you are actually using the variables you are establishing in the block, you can directly output your list using %%a, etc, not %hexcode% or !hexcode!. Without further information about how you intend to use these variables elsewhere, this may or may not be useful in your case.
BTW - 1,2,3... is not incorrect syntax, but 1-7 is shorter and means the same in this context.
I have a simple text file containing one file name per file. I want to merge all of these files. My plan for this was to read the text file, build a string like "filename1+file2+f3" and then use that as a parameter to copy /b.
However, I am having trouble reading the file correctly.
Here is what I have right now:
SET x=
FOR /F %%G IN (merge.txt) DO SET x=%x%+%%G
ECHO %x%
However, the "recursion" here does not seem to work properly and %x% just gets set to "+fl", where fl is the last filename in the file.
How do I do this properly?
Your logic is correct, but you are just missing the delayed expansion usage.
SETLOCAL EnableDelayedExpansion
SET "x="
FOR /F %%G IN (merge.txt) DO SET x=!x!+%%G
ECHO %x%
REM Trim the leading +
SET x=%x:~1,999%
ECHO %x%
ENDLOCAL
Without the delayed expansion, %x% is only evaluated when the FOR loop starts, so it would be blank for each iteration. By enabling delayed expansion, !x! (the notation for this) is evaluated on each iteration so it will build the compound string you are looking for.
I am trying to write a batch file that reads each line in a text file and assigns it (each line) to a variable.
I am using the example found here: Read each line in a txt file and assign variables using windows dos commands, which is:
SETLOCAL EnableDelayedExpansion
SET count=1
FOR /F "tokens=* delims= usebackq" %%x IN ("%TEXT_T%") DO (
SET var!count!=%%x
SET /a count=!count!+1
)
ENDLOCAL
Now, all I want to do is echo the results of each variable, but I just can't seem to be able to do so. Below is what I have, which gives me the results for var0 three times--my text file has three lines. I changed the start of count from the above code from 1 to 0.
#echo off
SETLOCAL EnableDelayedExpansion
SET count=0
FOR /F "tokens=* delims= usebackq" %%x IN ("afile.txt") DO (
SET var!count!=%%x
echo !var%count%!
SET /a count=!count!+1
echo !count!
)
ENDLOCAL
While this code
echo !var%count%!
seems logic, as count is changed inside the loop, you can not access the value of the variable without delayed expansion. But
echo !var!count!!
^...^ ^^
first variable second "variable"
will not work, as the parser is not able to properly determine where each variable reference start/end
You can use any of the two following lines
for %%a in (!count!) do echo !var%%a!
call echo %%var!count!%%
How does it work?
The original idea is good, but there are limits in the syntax. We need delayed expansion over the var.. variable, but also over the count.
1.- In the first solution, we store the delayed expansion of the count variable inside the for replaceable parameter, that is used instead of the count variable in the echo command, keeping the delayed expansion only around the var variable.
!var!count!! => %%a=!count! => !var%%a!
2.- In the second solution, a call command is used. This call causes a double evaluation of the line, first on the line parse to execute the call, second while call execution. That is, the line
call echo %%var!count!%%
is first parsed, and the only variable referenced in it is !count! (a double percent sign is a single escaped percent sign), so the line is translated into (suppose count contains 5)
call echo %var5%
Now, the call is executed, line is parsed again to execute the echo and the value of the correct variable is retrieved.
I am fighting with little piece of code for last two days.
In this I am not able to set variable in a for loop.
I want to assign a filename to a variable for string manipulation.
echo off
for /f %%a IN ('dir /b *_ah.ttf') DO (
set /a fName=%%~na
echo %fName%
)
When I echo fName variable I get only last filename repeatedly number of times for for loop count.
(I want to pass this variable as an argument to some batch file as follows
ttfhnt --strong-stem-width=D -i %%a %fName:~0,-3%.ttf
but its failing due to above problem)
Can somebody help me please?
When the cmd parser reads a line or a block of lines (the code inside the parenthesis), all variable reads are replaced with the value inside the variable before starting to execute the code. If the execution of the code in the block changes the value of the variable, this value can not be seen from inside the same block, as the read operation on the variable does not exist, as it was replaced with the value in the variable.
This same behaviour is seen in lines where several commands are concatenated with &. The line is fully parsed and then executed. If the first commands change the value of a variable, the later commands can not use this changed value because the read operation replace.
To solve it, you need to enable delayed expansion, and, where needed, change the syntax from %var% to !var!, indicating to the parser that the read operation needs to be delayed until the execution of the command.
And set /A is only used for arithmetic operations
setlocal enabledelayedexpansion
for /f "delims=" %%a IN ('dir /b *_ah.ttf') DO (
set "fName=%%~na"
echo "!fName!" "!fName:~0,-3!"
)
edited to adapt to comments
While for command is able to execute a command (in the OP code, the dir...), retrieve its output and then iterate over the lines in this output, the original reason for the command is to iterate over a set of files. In this form, the code can be written as
setlocal enabledelayedexpansion
for %%a IN ("*_ah.ttf") DO (
set "fName=%%~na"
echo "!fName!" "!fName:~0,-3!"
)
Now, the for command replaceable parameter will iterate over the indicated set of files. (execute for /? for a list of all the command options).
But as foxidrive points, the problem with delayed expansion are the exclamation signs. Without delayed expansion, they are another normal character, but with delayed expansion they frequently become a problem when a value containig them is assigned/echoed.
A quick test
#echo off
setlocal enabledelayedexpansion
set "test=this is a test^!"
echo ---------------------
set test
echo ---------------------
echo delayed : !test!
echo normal : %test%
for /f "delims=" %%a in ("!test!") do echo for : %%a
Will show
---------------------
test=this is a test!
---------------------
delayed : this is a test!
normal : this is a test
for : this is a test
Obviously when the value is a file name, this behaviour will make the code find or not the file.
Depending on the case different solutions can be used, but usually it involves the activation / desactivation of the delayed expansion behaviour (beware, the endlocal removes any change in environment variables from the previous setlocal).
#echo off
setlocal enabledelayedexpansion
set "test=this is a test^!"
echo ---------------------
set test
echo ---------------------
echo delayed : !test!
rem Commuted to no delayed expansion
setlocal disabledelayedexpansion
echo normal : %test%
endlocal
rem Cancelled the initial enable delayed expansion
for /f "delims=" %%a in ("!test!") do endlocal & echo for : %%a
rem The last endlocal has removed the changes to the variable
echo no data : [%test%]
I have a problem removing trailing \ in a script, my current script is:
echo on
setlocal enableextensions enabledelayedexpansion
SET SCRIPTFOLDER=C:\install$
FOR /F "tokens=* delims=," %%a in (%SCRIPTFOLDER%\GetFilesandFoldersFromHere.Txt) DO (
set data.path=%%~pa
SET data.path=%data.path:~0,-1%
echo %data.path%
rem echo file and folder= %%~na%%~xa Folder=%data.path%
)
The GetFilesandFoldersFromHere.Txt file has lines of files and location e.g.:
T:\First File Here\Move this File.txt
When I run the above code I get:
C:\install$\file Archive Scripts>(
set data.path=\First File Here\
rem If ~-1data.path:~0,0
SET data.path=~0,-1
echo
rem echo file and folder= Move this File.txt Folder=
I want to assign data.path the directory (without drive letter and the trailing ). It assigns the value but when I try to get rid of the trailing \ the value is nulled.
Does anyone have an idea whta is wrong with the code? I am sure it is a simple solution. Been banging my head against this screen, can't see the woods from the tree at the moment.
The problem is that when the for code block (the code enclosed in parenthesis) is parsed, all the variable read operations are replaced with the value in the variable before starting to execute, and in each iteration what is used is this initial value, and not the value stored into the variable during the execution.
If you change a variable inside a block of code and need to access the changed value inside the same block of code, you need to enable delayed expansion (setlocal enabledelayedexpansion) and change (where necessary) the syntax to access the variables to use !varName! instead of %varName%. This indicates to the parser that this read operation must be delayed.
So, in your code you have delayed expansion enabled, but
SET data.path=%data.path:~0,-1%
echo %data.path%
should be something like
SET data.path=!data.path:~0,-1!
echo !data.path!
Here's a trick to remove the trailing backslash
#echo off
set "folder=c:\data\"
for %%a in ("%folder%\.") do set "folder=%%~dpnxa"
set fold
pause