0

I have a requirement to generate a simple .BAT script/file. I assumed it to be easy but how wrong I was :-(

The BAT script has to (I believe):

  1. Take a const searchstring to search for
  2. Take an absolute folder path to a "start" directory
  3. Take a filename mask/regular expression to search for
  4. Take a const string to be "appended" to the content of the file
  5. Recursively iterate through all files in the start directory and subdirectories (n level down) searching (and "processing") any files that match the filename mask/regular expression
  6. Search the content of the "current" file (all "are text" files that can be opened in NOTEPAD), for the searchstring. The searchstring may be found 0, 1 or many times anywhere in the file.
  7. If searchstring is found, then do nothing. If the searchstring is not found then append the new string to the end of the file. Voila! (in theory)

Heres what I have already, not really working. I have several problems that I can see. How to get the "current file" and possibly also how to "reset" the ERRORLEVEL after each file.

SET SEARCHSTRING="search for this text"
SET STARTPATH="C:\StartFolder\*"
SET MATCHFILES="*.txt"
SET APPENDSTRING="Appended text"
findstr /c:%SEARCHSTRING% /b /i /d:%STARTPATH% %MATCHFILES%
SET FOUND=%ERRORLEVEL%
REM 0=true, 1=false
IF %FOUND%==1 (
                REM ISSUE: How to get "current" file path???
                REM %APPENDSTRING% >> %CURRENTFILEPATH%
              )

Any questions/suggestions more than welcome

Cheers

kyle

Kyle
  • 951
  • 3
  • 14
  • 31
  • To access the result of the findstr you can either use FOR to loop the candidate files individually and then another FOR to read the result, or redirect the findstr result to a file then parse that, see http://stackoverflow.com/questions/8942211/extract-found-line-subsequent-line-from-a-text-file for the idea – Alex K. Oct 26 '12 at 10:38

1 Answers1

0

I generally prefer to not include enclosing quotes in my variable values. I then add the enclosing quotes as needed at expansion time. Instead of set var="value", I like to use set "var=value". If I need enclosing quotes later on then I use "%var%".

Note: none of my code below has been tested. There could be some silly bugs, but I am confident the overall concepts are sound

The following simple script should handle most situations. The /M option is used so that FINDSTR does not waste its time searching every line for multiple - it exits as soon as it finds a single line that matches.

@echo off
setlocal
set "SEARCHSTRING=search for this text"
set "STARTPATH=C:\StartFolder"
set "MATCHFILES=*.txt"
set "APPENDSTRING=Appended text"
for /r "%STARTPATH%" %%F in ("%MATCHFILES%") do (
  >nul findstr /mbic:"%SEARCHSTRING%" "%%~F" || >>"%%F" echo(%APPENDSTRING%
)

But there are many scenarios that could break the above code.

  • Poison characters like unquoted &, | etc. could cause problems when expanding %APPENDSTR%

  • Poison characters could cause problems when expanding "%SEARCHSTRING%" if SEARCHSTRING also contains quotes.

  • FINDSTR has awkward escape rules for \ and " characters within the literal search string.

  • FINDSTR may not work properly if the SEARCHSTRING has certain byte codes > 128.

See What are the undocumented features and limitations of the Windows FINDSTR command? for more info about complexities of using FINDSTR

The easiest way to make the code work in all situations is to use delayed expansion to avoid problems with poison characters in variable values, and to store the search string in a temp file and use the FINDSTR /G option. Any \ character within the search string must be escaped as \\. Delayed expansion must be disabled within the FOR loop so that file names that contain ! are not corrupted.

@echo off
setlocal disableDelayedExpansion
set "SEARCHSTRING=search for this text"
set "STARTPATH=C:\StartFolder"
set "MATCHFILES=*.txt"
set "APPENDSTRING=Appended text"

set "tempFile=%temp%\search%random%_"
setlocal enableDelayedExpansion
>"%tempFile%search.txt" echo(!SEARCHSTRING:\=\\!
>"%tempFile%append.txt" echo(!APPENDSTRING!
endlocal

for /r "%STARTPATH%" %%F in ("%MATCHFILES%") do (
  >nul findstr /mbig:"%tempFile%search.txt" "%%~F" || type "%tempFile%append.txt" >>"%%~F"
)

del "%tempFile%*.txt"
Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390