3

I've been working on a BAT file which will delete old files based on creation date. To do this I've generated a list of all files and paths, then a list of files names to be protected. FINDSTR is then used to remove these files from the list of files and paths.

This system works fine until I encounter a file with a dash (or so it seems!)

Here's an example:

cleaner_protect.txt contains:

New File.txt 
New File - Copy.txt

cleaner_fullpath.txt contains:

P:\New File.txt
P:\New File - Copy.txt
P:\Old File.txt

I want to remove the New Files stored in cleaner_protect.txt from the cleaner_fullpath.txt, leaving the Old Files behind which I will later delete (not up to that bit yet lol). Here is my code so far:

:: Remove protected files from list to be deleted (fullpath)
:RemoveFile
:: load string into variable
set /p target= <cleaner_protect.txt
:: remove protected file from full path list
echo -----------------------------
echo Searching for: "%target%"
echo -----------------------------
pause
findstr /v ".\<%target%\>." cleaner_fullpath.txt > cleaner_temp.txt
echo -----------------------------
type cleaner_temp.txt
echo -----------------------------
pause
del cleaner_fullpath.txt
ren cleaner_temp.txt cleaner_fullpath.txt
:: Count remaining lines in list
Set target=cleaner_protect.txt
Set /a lines=0
For /f %%j in ('Find "" /v /c ^< %target%') Do Set /a lines=%%j
Echo %target% has %lines% lines.
pause
:: Loop until completed
IF %lines% GTR 0 (
:: Remove line from protected list
    more +1 cleaner_protect.txt > cleaner_temp.txt
    del cleaner_protect.txt
    ren cleaner_temp.txt cleaner_protect.txt
    set /a lines-=1
    GOTO :RemoveFile
)

Pauses and echos are for debugging purposes... I want this to run almost invisibly.

Can anyone shed some light on this? I need this code to repeatedly go through a dropbox and delete old files which may be in various levels of structure.

Domenic
  • 31
  • 1
  • 2
    What part of the batch fails, what you get and what you expect? – jeb Mar 16 '17 at 09:09
  • I would try with `findstr /v /r /c:"\<%target%\>"` – MC ND Mar 16 '17 at 09:27
  • @jeb It seems to fail at `findstr /v ".\<%target%\>." cleaner_fullpath.txt > cleaner_temp.txt` when `%target%` contains a dash. If `%target%` contains `New File.txt` then the process works just fine. However, if `%target%` contains `New File - Copy.txt` then the output cleaner_temp.txt is blank and contains no data, which then overwrites the cleaner_fullpath.txt file. I am expecting the output cleaner_temp.txt (and hence cleaner_fullpath.txt) to have the target string removed from the file. – Domenic Mar 20 '17 at 20:48
  • @MCND When I add the `/r /c` switches, the command line echoes `FINDSTR: /c ignored` at the point of reaching a target string (ie, file name) which contains a dash and still produces the same blank output text file. – Domenic Mar 20 '17 at 20:58
  • @Domenic, `/v /r /c:"regularexpression"` Did you include the colon? – MC ND Mar 20 '17 at 21:22
  • @MCND Sorry you're right, thanks for picking up on that. When I run FINDSTR with those `/r /c` switches it doesn't identify the searched string in the text file and just outputs an identical file to `cleaner_temp.txt`. I'm not sure if it will help but I've uploaded the `cleaner_protect.txt` and `cleaner_fullpath.txt` generated when I run my code on some of my real files. They can be found [here](https://drive.google.com/open?id=0B8OfbcASldFgenlvMEZsS1RFT2c). This is really bugging me! – Domenic Mar 20 '17 at 22:54
  • @Domenic, After seeing the files, your problem with `findstr` and the contents of the files is that `cleaner_protect.txt` has spaces at the end of each line. Once removed, the command `findstr /l /e /v /g:cleaner_protect.txt cleaner_fullpath.txt` should do what you need. – MC ND Mar 21 '17 at 07:36
  • @MC ND, perfect thanks for spotting that. I had to insert some code to remove the trailing spaces and now it's all working nicely. Thanks! – Domenic Mar 22 '17 at 04:15

2 Answers2

1

Maybe this simple line does all you want:

findstr /E /V /G:cleaner_protect.txt cleaner_fullpath.txt > cleaner_temp.txt

Sample output:

P:\Old File.txt
  • Wow... so this solution works extremely well on my example files, however does not work properly at all with my real files. How frustrating! FINDSTR seems to generate an output file that matches the original (nothing is removed). I've uploaded the text files generated when I run my code on some of my real files, can you see any reasons why this wouldn't work? The files are [here](https://drive.google.com/open?id=0B8OfbcASldFgenlvMEZsS1RFT2c) – Domenic Mar 20 '17 at 21:56
  • Here is an interrogation of [findstr flaws/bugs](http://stackoverflow.com/questions/8844868/what-are-the-undocumented-features-and-limitations-of-the-windows-findstr-comman) and we may have hit one I wasn't aware off. I'm looking into this but running out of time ATM. –  Mar 20 '17 at 22:19
  • Thanks very much for the help. I had looked through that list earlier but didn't notice anything that would explain this issue. – Domenic Mar 20 '17 at 22:38
  • Just tested @aschipl's batch with your above provided data (why didn't you post this first place?) and it also doesn't work with that data as expected. –  Mar 20 '17 at 22:41
  • Some of the content is sensitive so I had to change quite a lot of it before posting. And no, @aschipl's batch doesn't work with it either... I've tried a series of varying filenames to try and identify what's causing the problem but to no avail. Either way, I can't control the filepaths or names so it may be fruitless if FINDSTR simply won't play ball with them. – Domenic Mar 20 '17 at 23:00
0

I would do it as follows:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem /* Prepend each line of `cleaner_protect.txt` with `\\`, remove a trailing space,
rem    if applicable, and write result to `cleaner_temp.txt`: */
> "cleaner_temp.txt" (
    for /F "usebackq delims= eol=|" %%E in ("cleaner_protect.txt") do (
        set "ITEM=\\%%E|"
        setlocal EnableDelayedExpansion
        echo !ITEM: ^|=!
        endlocal
    )
)

rem /* Search `cleaner_fullpath.txt` for lines that do not end in any of the lines of
rem    `cleaner_temp.txt` and process the returned items only: */
for /F "delims= eol=|" %%F in ('
    findstr /V /I /E /L /G:"cleaner_temp.txt" "cleaner_fullpath.txt"
') do (
    ECHO del "%%F"
)

rem // Clean up temporary file `cleaner_temp.txt`:
del "cleaner_temp.txt"

endlocal
exit /B

After having tested the script, remove the upper-case ECHO command.

Supposing cleaner_protect.txt contains this:

New File.txt
New File - Copy.txt

The temporary file cleaner_temp.txt is going to contain this:

\\New File.txt
\\New File - Copy.txt

So having the text file cleaner_fullpath.txt:

P:\New File.txt
P:\New File - Copy.txt
P:\Old File.txt

Only the following items are processed:

P:\Old File.txt

The leading \\ is taken as one literal \ by findstr (as it uses the \ as an escape character).

The prefix \\ is implemented in order to cover also the following situations:

  1. Let us assume cleaner_protect.txt holds this:

    New File.txt
    

    And cleaner_fullpath.txt holds this:

    P:\New File.txt
    P:\Very New File.txt
    

    Without the prefix, P:\Very New File.txt would also match New File.txt at the end, hence it would not become deleted erroneously.

  2. Then let us assume cleaner_protect.txt holds this:

    .File.txt
    

    And cleaner_fullpath.txt holds this:

    P:\.File.txt
    P:\Other.File.txt
    

    With a \ prefix, P:\Other.File.txt would also match \.File.txt at the end, because . is a meta character to findstr (even though literal search strings are defined by /L, but escaping like \. still applies and results in a literal .), hence it would also not become deleted erroneously. However, with a \\ prefix, escaping applies to the second \, so a literal \ is the result; the . does not need to be escaped with the /L option.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Thanks so much for this detailed explanation. This solution picks up on a few oversights of my original method. As with above, however, whilst this works on my example files it doesn't work on my real files. It still marks the new files for deletion. There must be something wrong with the filename syntax?? I've uploaded the text files generated when I run my code on some of my real files, can you see any reasons why this wouldn't work? The files are [here](https://drive.google.com/open?id=0B8OfbcASldFgenlvMEZsS1RFT2c) – Domenic Mar 20 '17 at 22:35
  • Are there trailing spaces in the file `cleaner_protect.txt`, like you have in the example shown in your question? remove them and it is going to work as you expect... – aschipfl Mar 21 '17 at 09:57
  • perfect thanks for spotting that. I had to insert some code to remove the trailing spaces and now it's all working nicely. Thanks! – Domenic Mar 22 '17 at 04:15
  • You're welcome! My last edit also removes a trailing space from every line during creation of `cleaner_temp.txt`... – aschipfl Mar 22 '17 at 09:12