new to batch. I've narrowed down my problem to how batch variables are evaluated I think.
setlocal enableextensions enabledelayedexpansion
set timelimit=30
for /F "USEBACKQ tokens=4,6,8" %%a in (`systeminfo ^| qgrep -e "System Up Time:"`) do set /A timepassed=%%a*24*60+%%b*60+%%c
IF "!timepassed!" LEQ "%timelimit%" (
echo %timelimit%
) ELSE (
echo !timepassed!
)
When run, I expect the batch to output !timepassed! (1250 currently) however, it always outputs %timelimit% (30), leading me to believe that the LEQ IF is being taken, which makes no sense to me.
as suggested, try the following changes in your code
set the variable value using /A option
set /a timelimit=30
and compare the values with
IF !timepassed! LEQ !timelimit! (
Related
I'm a biologist, with no coding knowledge, trying to create a script that reads every *rprt.txt file in a folder.
In line 11 of each file, the fifth word is a number, If that number is 6000<number<14000 then I want to read the fifth word in line 13 and if that number is greater than 600. Copy the file into another folder in that directory.
At this point I've tried a lot of things. I know the next code is exiting the loop but is the best I got.
#echo off
for %%f in (*rprt.txt) do set "name=%%f" &goto first
:first
for /F "skip=10 tokens=5" %%i in (%name%) do set "var1=%%i" &goto nextline
:nextline
for /F "skip=12 tokens=5" %%i in (%name%) do set "var2=%%i" &goto nextline2
:nextline2
if %var1% geq 6000 (if %var2% geq 600 echo.%name% >> valid.txt)
I've also tried this to test the for loop but I don't understand what's wrong. This prints "echo is off" 3 times
#echo off
for %%f in (*rprt.txt) do (set "name=%%f" & echo %name% >> valid.txt)
#ECHO OFF
SETLOCAL
rem The following settings for the directories and filenames are names
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
FOR %%e IN ("%sourcedir%\*rprt.txt") DO (
rem %%e has filename
SET "line11="
FOR /f "usebackqskip=10tokens=5" %%y IN ("%%e") DO IF NOT DEFINED line11 (
SET "line11=y"
SET "line13="
FOR /f "usebackqskip=12tokens=5" %%o IN ("%%e") DO IF NOT DEFINED line13 (
SET "line13=y"
IF %%y gtr 6000 IF %%y lss 14000 IF %%o gtr 600 ECHO COPY "%%e" "%destdir%"
)
)
)
GOTO :EOF
Always verify against a test directory before applying to real data.
Note that if the filename does not contain separators like spaces, then both usebackq and the quotes around "%%e" can be omitted.
I'm assuming that the values in token 5 of the two lines are guaranteed numeric.
You were definitely on the right track, but the code for validating that something is a number can get kinda weird if you're not used to seeing it (in this case, I remove everything that isn't a digit and then return 1 if there's anything remaining) and the way that GTR and LSS work can also be confusing since it's based on ASCII values so words report as greater than numbers.
The script expects the reports to be in their own folder and the output folder to be in its own folder, and both of these folders should be in the same folder as the script, as opposed to the script being in the same folder as the input files.
#echo off
setlocal enabledelayedexpansion
set "input_directory=%~dp0\input"
set "output_directory=%~dp0\output"
pushd "%input_directory%"
for %%A in (*_rprt.txt) do (
for /f "tokens=5" %%B in ('findstr /n /r "^" "%%~A" ^| findstr "11:"') do set "line_11_num=%%B"
for /f "tokens=5" %%B in ('findstr /n /r "^" "%%~A" ^| findstr "13:"') do set "line_13_num=%%B"
call :isNumber !line_11_num! n[11]
call :isNumber !line_13_num! n[13]
set /a "valid_report=!n[11]!+!n[13]!"
if "!valid_report!"=="0" (
if !line_11_num! GTR 6000 if !line_11_num! LSS 14000 (
if !line_13_num! GTR 600 (
copy "%%~A" "%output_directory%"
)
)
)
)
exit /b
::------------------------------------------------------------------------------
:: Determines if a given string is a positive integer
::
:: Arguments: %1 - The value to check
:: %2 - The variable to store the result in
:: Returns: 0 if the number is a positive integer, 1 otherwise
::------------------------------------------------------------------------------
:isNumber
set "is_number=0"
for /f "delims=0123456789" %%A in ("%~1") do set "is_number=1"
set "%~2=%is_number%"
exit /b
The files and lines processed by for /F command must be processed completelly until the file ends; you can not "cut" the process at the middle with a goto command because the whole process is cancelled.
This means that all lines of all files must be processed with nested for /F commands and you must insert some type of control in order to "omit" the rest of lines that are not the 11 or 13. If the files are numerous or very large, this can take some time.
You can also take just the lines 11 and 13 via findstr commands, but anyway the execution of a couple of findstr commands connected via a pipe also takes some time.
You must be aware that any variable that takes its value inside a compound command (like for or if) must be accessed using !delayedExpansion! instead of %standardExpansion%. There are a lot of questions/answers in this site about this point.
My solution below takes a different approach: it reads just the first 13 lines of each file via a redirection instead of for /F command or findstr. If the files are few and small, this method would be similar in time to the other ones. However, I think this method is simpler and easier to understand.
#echo off
setlocal EnableDelayedExpansion
rem Read every *rprt.txt file in this folder
for %%f in (*rprt.txt) do (
rem Read line 11 and 13 of this file via a redirection
< "%%f" (
rem Skip first 10 lines
for /L %%i in (1,1,10) do set /P "dummy="
rem Read line 11 and line 13
set /P "line11="
set /P "dummy="
set /P "line13="
)
rem Get the number in line 11 and compare it
for /F "tokens=5" %%i in ("!line11!") do set "num=%%i"
if 6000 lss !num! if !num! lss 14000 (
rem Get the number in line 13 and compare it
for /F "tokens=5" %%i in ("!line13!") do set "num=%%i"
if !num! gtr 600 copy "%%f" anotherFolder
)
)
I'm having an issue with the batch script I wrote below. If I take out the "if" statement, it works, but doesn't print out the %size%, if I leave the "if" statement it gives me an error about "0 was unexpected at this time."
I really don't see any syntax errors here, and if I leave echo on, I see the variables getting set with the proper values. Ultimately I want this to restore files if it detects they're in a bad state, but I'm a little confused as to why the variables don't seem to be working properly.
#echo off
set folder="C:/Somedir/"
set backupfolder="C:/Backupdir/"
set minbytesize=0
for /R "%folder%" %%I in (*) do (
set size=%%~zI
set file=%%~nxI
echo %file% is %size%
if %size% EQU %minbytesize% (
REM do something
)
)
pause
the old delayed expansion pitfall:
#echo off
setlocal enableDelayedExpansion
set "folder=C:/Somedir/"
set "backupfolder=C:/Backupdir/"
set "minbytesize=0"
for /R "%folder%" %%I in (*) do (
set "size=%%~zI"
set "file=%%~nxI"
echo !file! is !size!
if !size! EQU !minbytesize! (
REM do something
)
)
pause
endlocal
more you can find here: ss64.com/nt/delayedexpansion.html
Last some days i am stuck with my requirment.first i am explaining my logic.i am calculating the a specific line no of a file with some logic.then passing that to a function :copy_text.in this function i am copying data.txt file to output file with adding one more line (line i passed as parameter) inside the file.my issue that the code is now working fine,but taking 7 minute to copy 40k records.if i will comment the function :line_count,it is taking just 30 secs to process but i can not able to add that line in my output file.
i can not change this enabledelayedexpansion and disabledelayedexpansion parameters because i am facing lots of issue at the time of printing values from file.because my file value contains ! and % characters,and also the length of my each line is more then 3000 chars.
Exp:OtherInformation: 74.49% subsidiary of Sources: tps://pro/search/xyz/card/index.html?code=!121212#!121;
Only my problem is there in counting the lines of file to add the text in that particular line no.please suggest me how i will use this part to run the script quick.
#ECHO Off
echo.%time%
setlocal enabledelayedexpansion
set /a hold_list_line_no=0 (This value will come from different logic)
::>>>>>>>>>>>>>>>>>>>>>>>>
call :copy_text !hold_list_line_no!
endlocal
echo.%time%
pause
exit 0;
:copy_text
setlocal disabledelayedexpansion
set /a line=%~1
FOR /F "delims=" %%c IN (C:\Users\1519499\Desktop\data.txt) DO (
call :line_count
echo %%c>>output.txt
)
:line_count
SET /A i+=1
if %i% equ %line% (
type add_this.txt>>C:\Users\1519499\Desktop\output.txt
)
Try this:
#ECHO Off
echo %time%
setlocal enabledelayedexpansion
set /a hold_list_line_no=0 (This value will come from different logic)
::>>>>>>>>>>>>>>>>>>>>>>>>
call :copy_text !hold_list_line_no!
endlocal
echo %time%
pause
exit 0
:copy_text
set /a line=%~1, i=0
(FOR /F "delims=" %%c IN (C:\Users\1519499\Desktop\data.txt) DO (
SET /A i+=1
if !i! equ %line% type add_this.txt
setlocal disabledelayedexpansion
echo %%c
endlocal
)) > output.txt
This method avoids the call command and >> append redirection, that are inherently slow... You may also empty the environment before the copy_text loop:
:copy_text
setlocal enabledelayedexpansion
for /F "delims==" %%a in ('set') do set "%%a="
Let me start off by saying I am very new to this, and what little code I have cobbled together I found on this site.
In the end I need a batch that when ran will grab each folder name in a parent dir. and copy it to a text file named label1, label2, ect.
I started with pulling the lines from a directory list in a text file. I can get it to echo the last line to a file using Seth's code from this post
Windows Batch file to echo a specific line number
I made some modifications to try to put it in a loop and now I get nothing out.
If anyone can help me it would be much appreciated. Here is my code so far.
set /a "x=1"
set /a "lines=91"
:while1
if %x% leq %lines% (
for /f "tokens=*" %%a in ('findstr /n .* "Y:\Test\foldernametest.txt"') do (
set "FullLine=%%a"
for /f "tokens=1* delims=:" %%b in ("%%a") do (
setlocal enabledelayedexpansion
set "LineData=!FullLine:*:=!"
if "%%b" equ "%1" echo(!LineData!
echo title=!linedata! > Lable%x%.dat
set /a "x= x+1"
endlocal
goto :while1
)
)
setlocal enabledelayedexpansion
set /a x=1
set /a lines=91
:while1
if %x% leq %lines% (
for /f "tokens=*" %%a in ('findstr /n .* "Y:\Test\foldernametest.txt"') do (
for /f "tokens=1* delims=:" %%b in ("%%a") do (
if "%%b" equ "%x%" (
echo(%%c
echo title=%%c > Lable%x%.dat
set /a x= x+1
goto while1
)
)
)
endlocal
I'm reasonably sure this will work, as would
setlocal enabledelayedexpansion
set /a x=1
set /a lines=91
:while1
if %x% leq %lines% (
for /f "tokens=1* delims=:" %%a in ('findstr /n .* "Y:\Test\foldernametest.txt"') do if %%a==%x% (
echo(%%b
echo title=%%b > Lable%x%.dat
set /a x= x+1
goto while1
)
)
endlocal
The issue with your code is that endlocal terminates a setlocal and all of the environment changes that have taken place since the setlocal are backed out - the environment is restored to what it was when the setlocal was executed.
The consequence is that with your code, you are incrementing x (a grand name for a variable) and then the increment is backed out when the endlocal is executed.
So - put the entire routine in a setlocal/endlocal bracket. This has other advanteages - like if you execute a setlocal immediately after #echo off, then when the routine terminates, the environment is returned to its original state - it does not accumulate changes (normally additions of variables) as more and more batches are run.
Some of the other changes I've made are cosmetic. the quotes in a set /a are superfluous and so is the colon in a goto (with the sole exception of goto :eof)
Another problem you have was %1 (meaning "the first parameter to the routine") where you probably meant "%x%".
In the first code fragment, the output of the findstr is assigned to %%a and the inner for assigns that part of the findstr before the delimiter to %%b and that after to %%c. You evidently want to pick the line %%b equal to %x% so the code makes the comparison and if equal, outputs %%c (rest of line) and title=%%c to the file made from Lable and the line number. (You've spelled label incorrectly); then increments x and tries again.
The second piece of code is a simplification of the first. The line is read from the file and numbered, then split directly on the colon; %%a gets the number, %%b the rest of the line, so if %%a is the same as the number %x% then we want to do something (no quotes required, since %%a is a simple numeric string and x will also be numeric because it's never assigned to a string containing separators or empty).
The thing-to-be-done is to echo the line from the file (in %%b, bump the line number and start again...
newbie here who would appreciate some help. I'm trying to generate to generate random file names (i.e. for each file in the source directory, a different random alphanumeric figure should be generated)
The function that generates the random alphanumeric name works but when the value is returned to the main routine, it remains the same across all the files. Not sure where the problem is but I suspect it has something to do with delayed expansion.
#Echo Off
Setlocal EnableDelayedExpansion
dir "D:/Source" /b > List.txt
FOR /F %%i in (List.txt) DO (
CALL:Alpha Numb
echo !Numb!
md D:\Output\%%~ni
rar a -v50M -hpabc123 -m0 -ep "D:\Output\%%~ni\!Numb!.rar" "D:\Source\%%i"
)
goto:eof
:Alpha
Setlocal EnableDelayedExpansion
Set _RNDLength=40
Set _Alphanumeric=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
Set _Str=%_Alphanumeric%987654321
:_LenLoop
IF NOT "%_Str:~18%"=="" SET _Str=%_Str:~9%& SET /A _Len+=9& GOTO :_LenLoop
SET _tmp=%_Str:~9,1%
SET /A _Len=_Len+_tmp
Set _count=0
SET _RndAlphaNum=
:_loop
Set /a _count+=1
SET _RND=%Random%
Set /A _RND=_RND%%%_Len%
SET _RndAlphaNum=!_RndAlphaNum!!_Alphanumeric:~%_RND%,1!
If !_count! lss %_RNDLength% goto _loop
REM Echo %_RndAlphaNum%
ENDLOCAL & SET "%~1=%_RndAlphaNum%"
Exit /b