1

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)
Magoo
  • 77,302
  • 8
  • 62
  • 84
Esferiv
  • 13
  • 2

3 Answers3

1

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
SomethingDark
  • 13,229
  • 5
  • 50
  • 55
1
@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.

Magoo
  • 77,302
  • 8
  • 62
  • 84
0

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

   )

)
Aacini
  • 65,180
  • 12
  • 72
  • 108