Using if condition inside a for loop using batch script - batch-file

I have a script which need to be iterating through the file and checking a condition, when it meets condition every time corresponding values should be stored to a variable and displayed.
for /f "tokens=1,6,8 delims= " %%D in (test.txt) do (if %%D==01 (set x=%%I
set y=%%K)
echo %x% %y%)
Can some one help me on the above code?

The tokens are asigned to the nominated control (%%D) and then %%E, %%F.
Solution: replace %%I with %%E and %%K with %%F
BUT within a block statement ( a parenthesised series of statements) %var% refers to the value of var at the time the statement is parsed, that is, checked for validity, not at run-time, that is, as the value changes through the operation of the loop.
To see the value as it changes, the easiest method is to change the echo statement to
call echo %%x%% %%y%%
For more information, see any of hundreds of SO responses on the subject of delayed expansion.

It could be done as below.
#echo off
setlocal enableextensions enabledelayedexpansion
for %%F in ("C:\Users\JOhn\Desktop\Check\*.txt") do SET input=%%F
for /f "tokens=1-10 delims= " %%a in (%input%) do (
if %%a==01 (
set "_y=%%f"
set "_z=%%h")
echo %%a %%b %%c %%d %%e %%f %%g %%h %%i %%j !_y! !_z!)>>temp.txt

Related

Semicolons at beginning of the line, delims and FOR cycle

I cannot figure out how to correctly identify an empty/undefined variable having two semicolon one after one other or the line that starts with it.
This is the cycle:
for /F "delims=; tokens=1-7" %%m IN (testlist.txt) DO echo FUNCGROUP=%%r a=%%m b=%%n c=%%o d=%%p e=%%q f=%%s
I also tried adding "eol=;" and "......eol=" without success.
This is content of the first line of the file testlist.txt:
;xxxxxx;Active;;FALSE;con ter - dong;HWID000001;Item;sites/coll-
The result I need is, for the first cycle:
a=
b=xxxxxx
c=Active
d=
e=FALSE
f=con ter - dong
g=HWID000001
Thanks for any help.
To achieve that, you need to put a "NULL value" for empty fields in the lines of the file.
As there is no direct string substitution utilities with batch, you have to make substitutions beforehand to create "empty" fields. I suggest you to use a "NULL" character for empty fields like unbreakable space (Alt+0160).
In your case, this gives :
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /F "eol= tokens=*" %%l in (file.txt) DO (
SET "LINE=%%l"
SET "LINE=###!LINE:;;=; ;!###"
SET "LINE=!LINE:###;= ;!"
SET "LINE=!LINE:;###=; !"
SET "LINE=!LINE:###=!"
for /F "delims=; tokens=1-7" %%m in ("!LINE!") DO (
SET "RES=FUNCGROUP=%%r a=%%m b=%%n c=%%o d=%%p e=%%q f=%%s"
echo !RES: =!
)
)
Note that the SET "LINE=###!LINE:;;=; ;!###", SET "LINE=!LINE:###;= ;!" and the SET "LINE=!LINE:;###=; !" sections use the unbreakable space (Alt+0160) and replace beginning ";" with "Alt+0160;", the ending ";" with ";Alt+0160" and any following ";;" with ";Alt+0160;". The for loop parses then correctly the line, and next you just have to remove the unbreakable space to get "empty" variables.
EDIT: As brightly suggested by #jeb in the comments, you can also use quotes to handle empty fields. Each for loop variables can be then directly and simply unquoted.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /F "eol= tokens=*" %%l in (file.txt) DO (
SET "LINE=%%l"
SET "LINE=###^"!LINE:;=^";^"!^"###"
SET "LINE=!LINE:###^";=^"^";!"
SET "LINE=!LINE:;^"###=;^"^"!"
SET "LINE=!LINE:###=!"
for /F "delims=; tokens=1-7" %%m in ("!LINE!") DO (
echo FUNCGROUP=%%~r a=%%~m b=%%~n c=%%~o d=%%~p e=%%~q f=%%~s
)
)
Unfortunately, you have not provided sufficient information for what you intend to do with your empty field, so this is only a demonstration to provide you with output similar to that which you've indicated in your question:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Delims==" %%G In ("(Set Field[) 2>NUL") Do Set "%%G="
Set "i=0"
For /F UseBackQ^ Delims^=^ EOL^= %%G In ("testlist.txt") Do Call :GetFields "%%G"
Pause
GoTo :EOF
:GetFields
Set "Record=%~1"
Set /A i += 1
SetLocal EnableDelayedExpansion
Set "Index=1"
Set "Field[!Index!]=%Record:;=" & Set /A Index +=1 & Set "Field[!Index!]=%"
Echo(&Echo Record !i!
For /L %%G In (1,1,!Index!) Do If Not Defined Field[%%G] (Echo Field[%%G]=) Else Set Field[%%G]
Exit /B

Batch scripting not assigning variable as expected

I'm working on a batch script which will assign a variable string and then trim it. I'm facing two issues:
The variables are not assigning properly. It is taking last value from from the variable file.
The variables are not assigning the first time I run the script. I need to run the script second time to see if the variables have been assigned. On third run, I can see the trim is working.
My script looks like this:
#echo off
for /f "tokens=*" %%a in ('findstr "W3SVCWINSRVRHOSTS" "C:\Data\SiebelAdmin\Commands\file.txt"') do (
for /f "tokens=2 delims==" %%b in ("%%a") do (
for %%c in (%%b) do (
echo in loop
set str=%%c
echo %%c
echo.%str%
set str=%str:~-6%
echo.%str%
)))
The output looks like this on third run:
> C:\Users\parthod\Desktop>b.bat
in loop
xsj-uvapoms72
7.2.27
7.2.27
in loop
xsj-uvapoms82
7.2.27
7.2.27
in loop
172.17.2.26
7.2.27
7.2.27
in loop
172.17.2.27
7.2.27
7.2.27
You fell into the delayed expansion trap -- try this:
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=*" %%a in ('findstr "W3SVCWINSRVRHOSTS" "C:\Data\SiebelAdmin\Commands\file.txt"') do (
for /f "tokens=2 delims==" %%b in ("%%a") do (
for %%c in (%%b) do (
echo in loop
set str=%%c
echo %%c
echo.!str!
set str=!str:~-6!
echo.!str!
)))
endlocal & set str=%str%
In between the setlocal/endlocal block, delayed variable expansion is active. To actually use this feature enclose the variables by !! rather than %%.
Since setlocal sets up a new namespace for variables, the compound endlocal & set statement is required to transfer the value of str beyond the block.

Numbering text files in a folder

I have some text files placed in the same folder as a batch file. I need the batch file to echo the filenames without its extention line by line with a numbering. It has to be in alphabetical order. Also, it needs to store the file name into a variable fruitx where x is the number of its numbering. For example...
If I have three files in the folder:
Banana.txt
Cherry.txt
Apple.txt
I need the batch file to echo:
1) Apple
2) Banana
3) Cherry
Then, I need the variable %fruit1% be "Apple", %fruit2% be "Banana" and %fruit3% be "Cherry".
set x=0
for /F "tokens=* delims=" %%I in ('dir /b *.txt') do (
set /a x=x+1&echo %x%^) %%~nI&set fruit%x%=%%~nI)
echo %x%
Here is my code. It doesn't work and I can't figure out why. It echos 0 for each of the numberings instead.
Sorry if this sounds confusing. Thanks in advance!
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.
In your case, the problematic variable is x, that changes its value inside the loop and needs this value inside the same loop
#echo off
setlocal enableextensions enabledelayedexpansion
set "x=0"
for /f "delims=" %%a in ('dir /a-d /b /on *.txt 2^>nul') do (
set /a "x+=1"
echo !x!^) %%~na
set "fruit!x!=%%~na"
)
echo(---------------------------
set fruit
Also, an alternative approach without delayed expansion can be to filter the generated list of files with findstr to generate the number for each element
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "tokens=1,2 delims=:" %%a in ('dir /a-d /b /on *.txt 2^>nul ^| findstr /n "^"') do (
echo %%a^) %%~nb
set "fruit%%a=%%~nb"
)
echo(---------------------------
set fruit
#echo off
setlocal enableDelayedExpansion
set counter=0
for /f %%a in ('dir /b /a:-d /o:n *.txt') do (
set /a counter=counter+1
echo !counter! ^) %%~na
set "fruit!counter!=%%~na"
)
echo listing fruits
set fruit

batch wmi for loop

I'm having trouble using wmi in a for loop. I'm simply trying to grab the first number for the OS Version to differentiate between XP (5) and Win7 (6).
The following works fine by itself for querying a single machine.
for /f "tokens=1 delims=." %%a in ('wmic /node:%machine% os get version') do #for /f "tokens=1 delims=." %%b in ("%%a") do #set osver=%%b
echo %osver%
However once I attempt to put it in a for loop, I'm only getting a blank for %osver%
for /f %%G in (list.txt) do (
for /f "skip=2 tokens=2 delims=.," %%a in ('wmic /node:%%G os get version /format:csv') do #for /f "tokens=1 delims=." %%b in ("%%a") do #set osver=%%b
echo %osver%
) > results.txt
I'm assuming it's an issue with my skip/tokens/delims but I'm not sure how to figure out where exactly it's going wrong. Any variation on them that I've tried still results in a blank line.
You also dont have to set %%b to osver, if you only need to echo the value of %%b you may as well echo %%b because on its own it is a variable that is available only to the method in which it was declared.. you only make an instance variable if you are planning on using it outside the for body ..
So you should probably stick to enabledelayedexpansion if you wana use it elsewhere ...
also you should enclose your statements with parenthesis to to avoid code mix up ....
I'd say you're assuming wrong.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
So, I'd predict that call echo %%osver%% in place of echo %osver% would fix your problem.
OTOH, echo %%b would likely be easier and quicker.
for /f %%G in (list.txt) do (
for /f "skip=2 tokens=2 delims=.," %%a in (
'wmic /node:%%G os get version /format:csv'
) do for /f "tokens=1 delims=." %%b in ("%%a") do (
set osver=%%b
echo %%b
)
CALL echo %%osver%%
) > results.txt

Modifying variable values inside a For loop in Windows shell script

I need to perform operations on first 4 files in a folder. So, the counter variable has to increment during each operation of the For loop. The following piece of code:
#ECHO OFF
SETLOCAL
SET TESTDIR1=D:\Local Data\Shell Script\test folder 1
SET _transfer=XXXX
FOR /f "delims=" %%i IN ('dir "%TESTDIR1%\*" /b/a-d/o-d') DO (
SET _transfer=%_transfer:~1%
ECHO %_transfer%
)
prints "XXXX" for every iteration of the loop. Why might that be?
Try
FOR /f "TOKENS=1*delims=[]" %%i IN ('dir "%TESTDIR1%\*" /b/a-d/o-d^|find /n /v ""') DO (
if %%1 LEQ 4 echo %%j
)
Your approach doesn't work because batch replaces any %var% within a block (a parenthesised sequence of commands) with the value of var before the block is executed. See any number of SO questions related to delayed expansion for more info.

Resources