Line reading program does not work - batch-file

I have a program that reads the file and outputs a random file line number, but when it goes to output it, it just says "Echo is off" Is it possible to fix this?
Here is my code:
#echo off
setlocal enabledelayedexpansion
set Counter=1
for /f "tokens=* delims=" %%x in (Lists.txt) do (
set "Line_!Counter!=%%x"
set /a Counter+=1
)
set /a Counter=%random% * 100 / 32768 + 1
echo %Counter%
echo "%Line_!Counter!%"
::Just displays echo is off
pause

echo "!Line_%Counter%!" will work. (not very intuitive, but makes sense, if you think about it)

There are two problems in your code.
The first has been pointed by Stephan. If you read the answers to this question, you will see that the parser replaces variables referenced with percents before variables referenced with exclamation marks. So when the parsers tries to handle %Line_!Counter!%, !Counter! is still not replaced in the line so %Line_!Counter!% is an undefined variable and is replaced with nothing. The inverse (!Line_%Counter%!) works because when the parser reaches the line, the first substitution is the percent variable and the last the exclamation mark variable.
The second is a logic error. The line
set /a Counter=%random% * 100 / 32768 + 1
will not work as intended if the file has more or less than 100 lines. If it has more, the higher numbered lines will never be selected. If it has less lines, a high numbered non existing line can be selected and as it does no exist, you will again get an echo is off message trying to echo the variable.
#echo off
setlocal enabledelayedexpansion
set Counter=0
for /f "tokens=* delims=" %%x in (Lists.txt) do (
set /a Counter+=1
set "Line_!Counter!=%%x"
)
set /a "selected=%random% %% Counter + 1"
echo %selected%
echo "!Line_%selected%!"
pause

Related

Batch file - loop through first n lines of text file

I'm trying to determine the format of a text file by looping through the first 10 lines, perform some regex matching and then compare the results at the end. I can easily loop through the entire file, but I only want the first N lines (in this case 10)
I'm familiar with other languages, but the idiosyncrasies of this batch file is throwing me for a loop so to say.
Here is what I have so far:
#echo off
setlocal enableDelayedExpansion
set /A REGEXCOUNTER=0
set /A COUNTER=0
for /F %A in (%submitfile%) do (
set /A COUNTER=COUNTER+1
rem echo %A
setlocal enableDelayedExpansion
echo(%A|findstr /r /c:"[0-9].*" >nul && (
set /A REGEXCOUNTER=REGEXCOUNTER+1
echo %COUNTER% - %REGEXCOUNTER% - FOUND - %A
rem any commands can go here
) || (
echo NOT FOUND
rem any commands can go here
)
rem LOOP END
if %COUNTER% GEQ 10 do (goto loop_over)
)
)
:loop_over
echo "END HERE!"
I've got counters set up that incrementally tick up to count my matches and how many times it's looped. However here is some sample output of variable values:
110 - 0 - FOUND - 003
220 - 0 - FOUND - 2
330 - 0 - FOUND - 1
440 - 0 - FOUND - 029
The loop counter variable is increasing by ten for each loop and the regex match counter is not going up at all. I'm pretty sure this has something to do with variable scope but I'm not sure where to begin.
This should fix all the issues I talked about in my comments above.
#echo off
setlocal enableDelayedExpansion
set /A REGEXCOUNTER=0
set /A COUNTER=0
for /F %%A in (%submitfile%) do (
set /A COUNTER=COUNTER+1
rem echo %%A
echo(%%A|findstr /r /c:"[0-9].*" >nul && (
set /A REGEXCOUNTER=REGEXCOUNTER+1
echo !COUNTER! - !REGEXCOUNTER! - FOUND - %%A
rem any commands can go here
) || (
echo NOT FOUND
rem any commands can go here
)
rem LOOP END
if !COUNTER! GEQ 10 goto loop_over
)
)
:loop_over
echo "END HERE"
The extra setlocal within the loop should be removed. Once setlocal enabledelayedexpansion has been executed, it remains in effect until a setlocal disabledelayedexpansion is executed or until the batch terminates.
Each %A (the loop-control metavariable must be %%A (one % if run from the command-line, two if within a batch file)
If you change the value of a variable within the loop, then you need to refer to the changed value as !varname!, not %varname% which is the original value (search SO for delayed expansion). set /a always works on the current variable value.

How to set and use global array variable in Batch file

Here is my code for storing the words extracted from a log file into an array, which I want to use in the batch file later on.
cls
#echo off
set /a i=0
TIMEOUT 2
REM I want to save the words from newlog.txt into an array for later use in batch file.
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1,2,3 delims= " %%G IN (newlog.txt) DO ( set a[%i%]=%%H
& set /a i+=1 #echo !a[%i%]! )
#echo %i%
#echo a[%i%]
TIMEOUT 200
I just want to use them as global variables.
#echo off
set /a i=0
REM I want to save the words from newlog.txt into an array for later use in batch file.
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1,2,3 delims= " %%G IN (q48428047.txt) DO (
set a[!i!]=%%H&set /a i+=1)
SET a[
pause
GOTO :EOF
I used a file named q48428047.txt containing some dummy data for my testing.
Note that %i% will be replaced by the value of i *as it was when the *forwas encountered that is, 0.
Your second set within your parentheses is incorrect. It's missing the & before the #echo. Also, you appear to be attempting to increment i and then show the corresponding array entry, which makes no sense because you haven't yet stored anything in that array-entry, you've attempted to install it in the previous position. It won't work anyway, because %i% will be replaced by 0, not the varying value of i.
And whereas you may get the count-of-lines appearing on the screen, a[numlines] will not be defined.
Use pause to stop the batch for perusal. Preferably, run the command from the prompt, not by clicking.
The modified code reads each line of the file putting the first word in %%G, second in %%H and third in %%I. it then assigns %%H to a[currentlinenumber] and increments the line number in i.
The set a[ will display all environment variables whose names start with a[.
In addition to the answer already provided, if you really have a need to Echo each variable value immediately after it is Set then you would need to invoke a Call command:
#Echo Off
Rem Undefine any existing variables which begin with a[
For /F "Delims==" %%A In ('"(Set a[) 2>Nul"') Do Set "%%A="
Set "i=0"
ClS
SetLocal EnableDelayedExpansion
For /F "UseBackQ Tokens=2 Delims= " %%A In ("newlog.txt") Do (
Set "a[!i!]=%%A"
Call Echo "%%a[!i!]%%"
Set /A i+=1
)
If %i% GEq 1 Echo(&Echo %i% variables were defined&Echo(
(Set a[) 2>Nul
Timeout 200

Fetch the max column count present in a file using batch (.BAT) programming

I have a test.csv file which has data something like this.
"a","usa","24-Nov-2011","100.98","Extra1","Extra2"
"B","zim","23-Nov-2011","123","Extra22"
"C","can","23-Nov-2011","123"
I want to fetch the maximum number of columns in this file (i,e 6 in this case) and then store this in a variable.
Like
Variable=6
I'm aware that this can be acheived in scripting as I have some basic knowledge about scripting. But I have zero programming knowledge in .BAT.
Please help me regarding this
#echo off
setlocal EnableDelayedExpansion
set variable=0
for /F "delims=" %%a in (test.csv) do (
set count=0
for %%b in (%%a) do set /A count=+1
if !count! gtr !variable! set variable=!count!
)
echo Variable=%variable%
This solution use the fact that strings enclosed in quotes in a FOR set are treated as individual items, so count they is very easy. For this reason, this method fail if there are wild-card characters ("*" or "?") in the lines.
If comma is your delimiter, maybe you could try to count the number of commas in every line and remember the biggest one (and increase it by one). (I assume, that commas are not in the strings)
count instances of a character in file per line : https://stackoverflow.com/a/7988661/2282321
edit:
I came up with following solution, please try it (assuming input file name with data to be 'a.txt'):
#echo off
set biggest_len=0
for /f "tokens=*" %%a in (a.txt) do call :processline %%a
echo %biggest_len%
goto :eof
:processline
set len=0
for %%b in (%*) do set /A len+=1
if %len% gtr %biggest_len% set /A biggest_len=len
goto :eof
:eof
sources I used to create solution:
Batch Script - Count instances of a character in a file
If greater than batch files
batch script - read line by line
#ECHO OFF
SETLOCAL
SET /a maxcols=0
SET /a mincols=999999
FOR /f "delims=" %%a IN (q28540735.txt) DO SET /a total=0&CALL :count %%a
ECHO maximum columns=%maxcols%
ECHO minimum columns=%mincols%
GOTO :EOF
:count
SET "$1=%~1"
IF DEFINED $1 SET /a total+=1&shift&GOTO count
IF %total% gtr %maxcols% SET /a maxcols=total
IF %total% lss %mincols% SET /a mincols=total
GOTO :EOF
I used a file named q28540735.txt containing your data for my testing.
Each line is presented to the subroutine count as comma-separated parameters, so if you set the total found to zero before each call, then it's a simple matter of counting the parameters. If the parameter presented is enclosed in quotes, then any commas and spaces within the quotes are processed as being part of the token, not separators in their own right.

batch programming

I am new in batch. Trying for some days to make something in batch but have a problem I cannot solve. I read a lot of your comments but did not find answer. Maybe you can help me?
The point is:
I input string from keyboard( e.g. 10 characters ). name of it is"allinputstring"
Calculate of length is ok ( by redirect in txt file and expand its bytes ). name "length"
Parse string in 10 pieces (strings) is ok.
So here is a problem, I want to echo these pieces, so I use next code, I use a counter to find out is the counter give me good count as output variable, and echo it to see on screen if it is good. Counter seems good, end echo of pieces strings is good enough. But I want to put in line 5. Variable count instead of "%%m", and cannot find a syntax way how to do it.
setlocal enabledelayedexpansion
for /l %%m in (1,1,!lenght!) do (
set /a count=0
set /a count=count+%%m
echo !count!!allinputstring:~%%m,1!
)
endlocal
please help me.
Try this:
#echo off &setlocal enabledelayedexpansion
set /a lenght=9
set "allinputstring=ABCDEFGHIJ"
for /l %%m in (0,1,%lenght%) do (
set /a count=0
set /a count+=%%m
echo !count! !allinputstring:~%%m,1!
)
endlocal
Output is:
0 A
1 B
2 C
3 D
4 E
5 F
6 G
7 H
8 I
9 J
#ECHO off
setlocal ENABLEDELAYEDEXPANSION
SET allinputstring=abcdefghijk
SET lenght=10
for /l %%m in (1,1,!lenght!) do (
set /a count=0
set /a count=count+%%m
FOR %%z IN (!count!) DO echo !count! !allinputstring:~%%z,1!
)
GOTO :eof
Does this do what you require?
So... to make COUNT show (I've assigned it to KOWNT, but the syntax endlocal&set count=%count% would assign it to COUNT instead)
I've changed the starting value of the FOR/L because character counting starts from character#0 in the string.
#ECHO off
setlocal ENABLEDELAYEDEXPANSION
SET allinputstring=abcdefghij
SET lenght=9
for /l %%m in (0,1,!lenght!) do (
set /a count=0
set /a count=count+%%m
FOR %%z IN (!count!) DO echo !count! !allinputstring:~%%z,1!
)
endlocal&SET KOWNT=%count%
ECHO Now KOWNT=%KOWNT% but count=%count% because we have exited the SETLOCAL
GOTO :eof
When the ENDLOCAL is encountered, the parser substitutes the CURRENT value of the variables in the line and THEN executes the line.
Hence, the line is executed as
endlocal&set KOWNT=9
since the value of count at the time is 9.
When the SETLOCAL is executed, all changes to the environment since the matching SETLOCAL are thrown away. The environment variables are restored to their state when the SETLOCAL was executed and count becomes empty again (as it was before the routine.) THEN the SET instruction is executed, which sets KOWNT to 9.

Arithmetic inside a for loop batch file

I have a for loop in a batch file that looks like this:
for %%y in (100 200 300 400 500) do (
set /a x = y/25
echo %x%
)
The line:
set /a x = y/25
Doesn't seem to be doing any division. What is the correct syntax for dividing each y by 25? I only need the integer result from this division.
Environment variables need not be expanded to use in a SET /A statement. But FOR variables must be expanded.
Also, even if your computation worked, the ECHO would fail because percent expansion takes place when a statement is parsed, and the entire FOR construct is parsed at once. So the value of %x% would be the value as it existed before the loop is executed. To get the value that was set within the loop you should use delayed expansion.
Also, you should remove the space before the assignment operator. You are declaring a variable with a space in the name.
#echo off
setlocal enableDelayedExpansion
for %%A in (100 200 300 400 500) do (
set n=%%A
REM a FOR variable must be expanded
set /a x=%%A/25
REM an environment variable need not be expanded
set /a y=n/25
REM variables that were set within a block must be expanded using delayed expansion
echo x=!x!, y=!y!
REM another technique is to use CALL with doubled percents, but it is slower and less reliable
call echo x=%%x%%, y=%%y%%
)
It's not doing anything because "y" is just a letter. You need percent signs to reference the variable.
set /a x = %%y/25
I was having the same issue but turned out to be an integer issue. I was multiplying after dividing but need to before. What was happening is something like this:
1/100x100 which operates like 1\100=0 then 0x100=0
I changed it to
1x100/100 which operates like 1x100=100 then 100/100=1
#echo off
setlocal ENABLEDELAYEDEXPANSION
for /f "usebackq" %%b in (`type List.txt ^| find "" /v /c`) do (
set Count=%%b
)
)
REM Echo !Count! -->Returns the correct number of lines in the file
for /F "tokens=*" %%A in (List.txt) do (
set cName=%%A
set /a Number+=1
REM Echo !Number! -->Returns the correct increment of the loop
set /a Percentage=100*!Number!/!Count!
REM Echo !Percentage! -->Returns 1 when on the first line of a 100 line file
set a=1
set b=1000
set /a c=100*1/100
Rem -->echo c = !c! --Returns "C = 1"
)

Resources