Find a string in a txt file matching a folder name

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Find a string in a txt file matching a folder name

#1 Post by julesverne » 19 Jan 2014 16:59

At wit's end today.

Task I'm faced with today is this:

Using a bat file (by doubleclicking on it) it will copy only certain folders (with a date in the title) to the bat file's directory that are NOT listed in a txt file but then add to a txt file what folder names were added.

1. It will first get current date in desired format. - problem solved.
2. It will first see if there is a txt file (which would be a list of folder names, one folder name per line). This txt file was created by this bat file running previously.
3. if the txt file doesn't exist.. copy folders that match the folder name criteria and then add those names to a txt file so that next time the bat is run, it will know to skip these folders.
4. if the txt file does exist.. copy only folders that match the folder name criteria that are NOT in the txt file... and then append those folder names to the txt file so that next time the bat is run, it will know to skip these folders.

So.. the code below is what I've come up with so far. The txt file is not getting appended correctly.. because the loops are going over and over everytime it's run. .. it's a mess.. and so is my brain at this point. Any help would be appreciated. It seems like.. this should work fine..

Code: Select all

@echo off

echo .. harvesting..

REM date parsing loop below will give date in form yyyymmdd to match Podium MR client folder name
FOR /F "tokens=1-3 delims=/-" %%A IN ("%DATE%") DO (
    SET DayMonth=%%A
    SET MonthDay=%%B
    SET Year=%%C
)
FOR /F "tokens=2 delims= " %%A in ("%DayMonth%") DO (SET Month=%%A)
setlocal enabledelayedexpansion


set /a counter=0
setlocal enabledelayedexpansion
for /f "usebackq delims=*" %%T in (`dir /ad /b "C:\Program Files\Company" ^| findstr /i "client-%Year%%Month%%MonthDay%*" `) do (
   set foldercheck=%%T
   if exist c:\collect.txt (
      for /f "usebackq delims=*" %%R in (`findstr /v "!foldercheck!" "C:\collect.txt"`) do (
            set folder=%~dp0%
            set folder=!folder:~0,-1!
            echo D | xcopy /s "c:\program files\Company\%%T" "!folder!\%%T" >nul
            set /a counter+=1
      )
   ) else (
   set folder=%~dp0%
   set folder=!folder:~0,-1!
   echo D | xcopy /s "c:\program files\company\%%T" "!folder!\%%T" >nul
   echo %%T >>C:\collect.txt
   )
)
pause



this was what I originally came up with that worked until I realized that it would keep copying all the folder names every time but.. maybe it's a springboard for someone if the other one is indecipherable.

Code: Select all

@echo off

echo .. harvesting..

REM date parsing loop below will give date in form yyyymmdd to match Podium MR client folder name
FOR /F "tokens=1-3 delims=/-" %%A IN ("%DATE%") DO (
    SET DayMonth=%%A
    SET MonthDay=%%B
    SET Year=%%C
)
FOR /F "tokens=2 delims= " %%A in ("%DayMonth%") DO (SET Month=%%A)

setlocal enabledelayedexpansion

for /f "usebackq delims=" %%c in (`dir /ad /b "C:\Program Files\company" ^| findstr /i "client-%Year%%Month%%MonthDay%*" `) do (
set folder=%~dp0%
set folder=!folder:~0,-1!
echo D | xcopy /s "c:\program files\company\%%c" "!folder!\%%c" >nul
)


if you a test folder name for debugging an example would be "client-20140119*"

Thanks in advance for any help. Jules

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Find a string in a txt file matching a folder name

#2 Post by foxidrive » 20 Jan 2014 07:18

The trick is creating a zero byte file if "C:\collect.txt" doesn't exist.

Findstr sets an errorlevel where || means execute the following if the text was NOT found.

Xcopy doesn't need the echo D when the trailing backslash is added to the end of the target path. Some extra switches copy folders more completely, when it is necessary.

Also delayed expansion isn't needed here.

Code: Select all

@echo off

echo .. harvesting..

:: The next four lines will give you reliable YY DD MM YYYY HH Min Sec variables in XP Pro and higher.

for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"

set "datestamp=%YYYY%%MM%%DD%"

set /a counter=0

for /f "delims=*" %%T in ('dir /ad /b "C:\Program Files\Company" ^| findstr /i "client-%datestamp%*" ') do (
   if not exist "c:\collect.txt" type nul >"c:\collect.txt"
   findstr /i "%%T" "C:\collect.txt" >nul || (
      xcopy /s/h/e/k/f/c "c:\program files\Company\%%T\*.*" "%~dp0\%%T\" >nul
      >>C:\collect.txt echo %%T
      set /a counter+=1
  )
)

echo %counter%

pause

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Find a string in a txt file matching a folder name

#3 Post by julesverne » 20 Jan 2014 07:47

Works perfect! Awesome! thanks!! I noticed that findstr didn't do anything if it didn't find anything but didn't see an error level so adding the || is a trick i didn't know.

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Find a string in a txt file matching a folder name

#4 Post by julesverne » 20 Jan 2014 08:10

@foxidrive

I was thinking about another addition to this that would be cool. It's code for calculating space availabilty before copying those folders. However, not sure if it's possible to implement it here. Aacini helped me with it last week. If I'm reaching for the stars.. no problem, just thought it would useful addition.

described here: viewtopic.php?f=3&t=5270#p31745

Code: Select all

@echo on
setlocal EnableDelayedExpansion

set file="C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob"

for %%F in (%file%) do set "filesize=%%~zF"
for /F "tokens=3" %%F in ('dir /-C "%~N0.bat"') do set "availableSpace=%%F"

call :DecimalToPowerOf1024 %filesize% %file%
call :DecimalToPowerOf1024 %availableSpace% %drive%

rem Test if availableSpace in drive is greater than filesize:

rem If there are more groups of numbers in drive than in file
if %drive% gtr %file% goto enoughSpace

rem If there are the same groups of numbers and drive number is greater than file number
if %drive% equ %file% if !drive[%drive%]! gtr !file[%file%]! goto enoughSpace

echo Not enough space
pause
goto :EOF

:enoughSpace
echo Enough space: proceed to copy
pause
goto :EOF


:DecimalToPowerOf1024

rem DecimalToPowerOf1024.bat bigNumber [arrayName]
rem Decimal to power-of-1024 base conversion of an unlimited size decimal number
rem Antonio Perez Ayala

rem Get the name of the array, if any
set power=PowerOf1024
if "%~2" neq "" set "power=%~2"

rem Divide the number in 9-digits groups, eliminating left zeros in each group
set number=%1
set groups=0
:nextGroup
   set group=%number:~-9%
   for /L %%a in (1,1,8) do if "!group:~0,1!" equ "0" set group=!group:~1!
   set /A groups+=1
   set group[%groups%]=%group%
   set number=%number:~0,-9%
if defined number goto nextGroup

rem Convert the 9-digits groups to power-of-1024 values
set /A bitPos=0, %power%=0, %power%[0]=0
:nextBinaryDigit
   rem Divide the 9-digits groups by 2
   set carry=0
   for /L %%i in (%groups%,-1,1) do (
      set /A term=carry*1000000000+group[%%i], group[%%i]=term/2, carry=term%%2
   )
   rem Insert remainder in current PowerOf1024 value, in right-to-left order
   set /A "%power%[!%power%!]+=carry<<bitPos, bitPos+=1"
   rem If current PowerOf1024 value completed: pass to next one
   if %bitPos% equ 10 set /A bitPos=0, %power%+=1 & set %power%[!%power%!]=0
   rem If last (most significant) group was completely converted: eliminate it
   if !group[%groups%]! equ 0 set /A groups-=1
   rem And pass to convert the rest of 9-digits groups
if %groups% gtr 0 goto nextBinaryDigit
for %%p in (!%power%!) do if !%power%[%%p]! equ 0 set "%power%[%%p]=" & set /A %power%-=1

exit /B

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Find a string in a txt file matching a folder name

#5 Post by foxidrive » 20 Jan 2014 08:55

julesverne wrote:Works perfect! Awesome! thanks!! I noticed that findstr didn't do anything if it didn't find anything but didn't see an error level so adding the || is a trick i didn't know.



The || actually executes when the previous program returned errorlevel 1 or higher.
Conversely the && operator executes when the previous program returned errorlevel 0 which is generally no error.

For free space, I offered the VBS solution which is far simpler and these days I lean to simpler and more robust solutions.

Clever involved solutions are well and good from an enthusiast point-of-view but when you look at the code to change it 12 months down the track,
even the person that wrote it thinks "wtf?" and has to study it well to remember how it worked.

If I can do something that is more obvious to read, plus being more robust, I'll usually pick that these days when it's helping others.

Post Reply