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
(как он использует \
как побег персонажа).
Префикс \\
реализуется для того, чтобы охватить также следующие ситуации:
Допустим
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
в конце, следовательно, он не будет удален по ошибке.Тогда давайте предположим,
cleaner_protect.txt
держит это:.File.txt
А также
cleaner_fullpath.txt
держит это:P:\.File.txt P:\Other.File.txt
С
\
префикс,P:\Other.File.txt
также будет соответствовать\.File.txt
в конце концов, потому что.
метасимволfindstr
(даже если строки поиска букв определяются/L
, но убегать как\.
все еще применяется и приводит к буквальному.
), следовательно, он также не будет удален по ошибке. Однако с\\
префикс, экранирование относится ко второму\
так буквально\
это результат;.
не нужно экранировать с/L
вариант.