9

I'm new to Windows batch programming and to Stack Overflow, so please forgive me if I ask anything that's blatantly obvious to you seasoned, talented folks. I'm using Windows batch (.bat) to find files containing a certain string using findstr. However, I'm trying to skip certain folders within a directory.

setlocal EnableDelayedExpansion
set basedir=C:\folder

for /f %%g in ('dir /a:-h /b %basedir% ^| findstr /v "Projects" ^| findstr /v "Archive"') do (
    findstr /i /m /s /c:"request" %basedir%\%%g *.* > %basedir%\Projects\list.txt
)

When I look in list.txt, the file output from findstr, I find that the folders I told it not to search were searched. That is, the output looks like this:

C:\folder\somefile.rtf
C:\folder\Requests\anotherfile.rtf
C:\folder\Projects\dontsearchme.txt
C:\folder\Archive\dontsearchmeeither.txt
C:\folder\Archive\Projects\dontsearchme.txt

If it had worked correctly, only C:\folder\somefile.rtf and C:\folder\Requests\anotherfile.rtf would have been included in list.txt. To test the looping code, I used the following:

setlocal EnableDelayedExpansion
set basedir=C:\folder

for /f %%g in ('dir /a:-h /b %basedir% ^| findstr /v "Projects" ^| findstr /v "Archive"') do (
    echo %basedir%\%%g
)

That code works as desired; it skips the Projects and Archive folders. I assume that the problem has something to do with how I'm calling findstr but I haven't been able to identify the error of my ways. Any insight would be much appreciated!

Thanks so much!
-Alex

Alex A.
  • 5,466
  • 4
  • 26
  • 56

4 Answers4

8

The FINDSTR /S option is causing it to search all folders, thus bypassing the intent of your FOR loop.

Stephan did successfully diagnose another problem with your code regarding redirection using overwrite instead of append mode.

But there is a much simpler method to get your desired result. Simply let FINDSTR search all folders, and pipe the result to an additional FINDSTR to remove results containing the unwanted folders. Since there is no loop, you can safely use owverwrite mode for redirection.

findstr /misl request "%basedir%\*" | findstr /liv "\\projects\\ \\archive\\" >"%basedir%\Projects\list.txt"

EDIT

The above simple solution will waste time searching folders that will later get excluded. This could waste valuable time if those folders are huge.

The following script will not bother scanning the "%basedir%\Projects" or "%basedir%\Archive" folders.

@echo off
setlocal EnableDelayedExpansion
set basedir=C:\folder

>"%basedir%\Projects\list.txt" (
  findstr /mil request "%basedir%\*"
  for /f "eol=: delims=" %%F in (
    'dir /a:d-h /b %basedir% ^| findstr /vixl "projects archive"'
  ) do findstr /smil request "%basedir%\%%F\*"
)

If you want to skip all folders named "Projects" or "Archive", regardless where they appear in the tree, then:

@echo off
setlocal EnableDelayedExpansion
set basedir=C:\folder

>"%basedir%\Projects\list.txt" (
  findstr /mil request "%basedir%\*"
  for /f "eol=: delims=" %%F in (
    'dir /s /a:d-h /b %basedir% ^| findstr /vir "[\\]projects[\\] [\\]archive[\\] [\\]projects$ [\\]archive$"'
  ) do findstr /mil request "%%F\*"
)
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • 1
    I love the simplicity. However, won't this find all of the files that contain "request," even in the unwanted folders, and then filter those results rather than only searching desired folders? It matters because I'm going to be running this on a huge directory. Thanks so much! – Alex A. Nov 19 '13 at 18:50
  • @Alex - Yes, it will wast time scanning excluded folders. See my updated answer for a script that will bypass excluded folders entirely. – dbenham Nov 19 '13 at 20:09
  • When I run this it still gets into the folders I don't want it to search. – Alex A. Nov 19 '13 at 22:11
  • @Alex - Yes, I forgot to remove the /S option on the looped FINDSTR in the first updated answser. All fixed now. – dbenham Nov 19 '13 at 22:16
  • Now it works and it works pretty quickly, but it now omits some files that the code @Aacini posted does catch. What is the difference in approach that would cause this? – Alex A. Nov 19 '13 at 23:14
  • @Alex - Actually, I had it right the first time. The /S option needs to be there within the loop, and it should filter out the Projects and Archive folders. The last solution was wrong, I needed to use a regex filter. Both should now work. – dbenham Nov 19 '13 at 23:43
6

I had a similar problem: I needed to use findstr to search all .js files except those in the node_modules folder (i.e., I wanted to search my code, but not the code of any imported modules). This is the command I used:

dir /S /B *.js | findstr /v /i node_modules | findstr /i /F:/ todo

Breaking that down:

  • dir /S /B *.js will output the full path of all .js files in the current directory and all subdirectories
  • findstr /v /i node_modules filters that list of paths and removes any path that contains the string "node_modules". (The /v flag makes findstr output lines that do not match.)
  • findstr /i /F:/ todo - The "/F:/" tells findstr to accept a list of file paths to search from the console.

So, only files that make it through the "node_modules" filter get searched.

Derek Kurth
  • 1,771
  • 1
  • 19
  • 19
1

your problem is: with the redirection > you overwrite your list.txt every time; the last time you overwrite it with an empty string. Use >> (append to file) instead. The rest of your code is working for me.

Stephan
  • 53,940
  • 10
  • 58
  • 91
  • When I use `>>` instead of `>`, I nothing is written to list.txt. Output to list.txt worked as expected using `>`. – Alex A. Nov 19 '13 at 17:59
  • You have identified a problem with the code, but it has nothing to do with the OP's stated question. The rest of the code is not working fine due to the FINDSTR /S option. – dbenham Nov 19 '13 at 18:09
0

Your code have a couple points difficult to follow. You want to skip folders, but for /f %%g in ('dir /a:-h /b %basedir% command get all non-hidden names, including both files and folders. At end you use > to store the results, so just the output of last findstr ... %%g is stored in that file. You must use >> instead as Stephan indicate. However, I still don't understand how you get that result!

I suggest you to modify your code in order to made it simpler, so it may be easier to follow and detect possible errors. For example:

setlocal EnableDelayedExpansion
set basedir=C:\folder
set omitfolders=\Projects\Archive\
cd %basedir%
for /D %%g in (*) do (
   if "!omitfolders:\%%g\=!" equ "%omitfolders%" (
       findstr /i /m /s /c:"request" %basedir%\%%g\*.* >> %basedir%\Projects\list.txt
   )
)

The if "!omitfolders:\%%g\=!" equ "%omitfolders%" command test if the folder name is not in omitfolders variable.

Aacini
  • 65,180
  • 12
  • 72
  • 108
  • I want to search the files in `%basedir%` as well as the files in the subfolders. It works if I include `findstr /imc:"request" %basedir%\*.* > %basedir%\Projects\list.txt` prior to the loop that appends to the file. Thanks so much for the help! – Alex A. Nov 19 '13 at 18:58