findstr не работает со строкой, содержащей тире (-)?

Я работал над BAT-файлом, который будет удалять старые файлы в зависимости от даты создания. Для этого я создал список всех файлов и путей, а затем список имен файлов, которые должны быть защищены. Затем FINDSTR используется для удаления этих файлов из списка файлов и путей.

Эта система работает нормально, пока я не столкнусь с файлом с тире (или так кажется!)

Вот пример:

cleaner_protect.txt содержит:

New File.txt 
New File - Copy.txt

cleaner_fullpath.txt содержит:

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

Я хочу удалить новые файлы, хранящиеся в cleaner_protect.txt, из cleaner_fullpath.txt, оставив старые файлы, за которыми я буду позже удалять (пока не до этого бита, лол). Вот мой код до сих пор:

:: 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
)

Паузы и эхо предназначены для отладки... Я хочу, чтобы это работало почти незаметно.

Может кто-нибудь пролить некоторый свет на это? Мне нужно, чтобы этот код неоднократно проходил через Dropbox и удалял старые файлы, которые могут иметь различную структуру.

2 ответа

Может быть, эта простая строка делает все, что вы хотите:

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

Образец вывода:

P:\Old File.txt

Я бы сделал это следующим образом:

@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

После проверки сценария удалите верхний регистр ECHO команда.

если бы cleaner_protect.txt содержит это:

New File.txt
New File - Copy.txt

Временный файл cleaner_temp.txt будет содержать это:

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

Таким образом, имея текстовый файл cleaner_fullpath.txt:

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

Только следующие предметы обрабатываются:

P:\Old File.txt

Ведущий \\ принимается за один буквальный \ от findstr (как он использует \ как побег персонажа).

Префикс \\ реализуется для того, чтобы охватить также следующие ситуации:

  1. Допустим cleaner_protect.txt держит это:

    New File.txt
    

    А также cleaner_fullpath.txt держит это:

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

    Без префикса, P:\Very New File.txt также будет соответствовать New File.txt в конце, следовательно, он не будет удален по ошибке.

  2. Тогда давайте предположим, cleaner_protect.txt держит это:

    .File.txt
    

    А также cleaner_fullpath.txt держит это:

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

    С \ префикс, P:\Other.File.txt также будет соответствовать \.File.txt в конце концов, потому что . метасимвол findstr (даже если строки поиска букв определяются /L, но убегать как \. все еще применяется и приводит к буквальному .), следовательно, он также не будет удален по ошибке. Однако с \\ префикс, экранирование относится ко второму \ так буквально \ это результат; . не нужно экранировать с /L вариант.

Другие вопросы по тегам