Я не могу сказать, почему findstr
может не работать с несколькими литеральными строками. Тем не менее, я могу предоставить метод, чтобы обойти эту досадную ошибку.
Учитывая, что строки литерального поиска перечислены в текстовом файле с именем search_strings.txt
...:
ffffaaa
faffaffddd
..., вы можете преобразовать его в регулярные выражения, вставив обратную косую черту перед каждым отдельным символом:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
> "regular_expressions.txt" (
for /F usebackq^ delims^=^ eol^= %%S in ("search_strings.txt") do (
set "REGEX=" & set "STRING=%%S"
for /F delims^=^ eol^= %%T in ('
cmd /U /V /C echo(!STRING!^| find /V ""
') do (
set "ESCCHR=\%%T"
if "%%T"="<" (set "ESCCHR=%%T") else if "%%T"=">" (set "ESCCHR=%%T")
setlocal EnableDelayedExpansion
for /F "delims=" %%U in ("REGEX=!REGEX!!ESCCHR!") do (
endlocal & set "%%U"
)
)
setlocal EnableDelayedExpansion
echo(!REGEX!
endlocal
)
)
endlocal
Затем используйте преобразованный файл regular_expressions.txt
...:
\f\f\f\f\a\a\a
\f\a\f\f\a\f\f\d\d\d
... чтобы выполнить поиск по регулярному выражению, который, кажется, хорошо работает и с несколькими строками поиска:
echo ffffaaa| findstr /R /G:"regular_expressions.txt"
Предыдущие обратные косые черты просто экранируют каждый символ, включая те, которые имеют особое значение при поиске по регулярному выражению.
Символы <
и >
исключены из экранирования, чтобы избежать конфликтов с границами слов, которые были выражены \<
и \>
при появлении в начале и в конце строки поиска. соответственно.
Поскольку регулярные выражения ограничены 254 символами для findstr
версий, предшествующих Windows XP (в отличие от буквенных строк, которые ограничены 511 символами), длина исходных строк поиска ограничена 127 символами, поскольку каждый такой символ выражается двумя символами из-за экранирования.
Вот альтернативный подход, который экранирует только метасимволы .
, *
, ^
, $
, [
, ]
, \
, "
:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "_META=.*^$[]\"^" & rem (including `"`)
> "regular_expressions.txt" (
for /F usebackq^ delims^=^ eol^= %%S in ("search_strings.txt") do (
set "REGEX=" & set "STRING=%%S"
for /F delims^=^ eol^= %%T in ('
cmd /U /V /C echo(!STRING!^| find /V ""
') do (
set "CHR=%%T"
setlocal EnableDelayedExpansion
if not "!_META!"=="!_META:*%%T=!" set "CHR=\!CHR!"
for /F "delims=" %%U in ("REGEX=!REGEX!!CHR!") do (
endlocal & set "%%U"
)
)
setlocal EnableDelayedExpansion
echo(!REGEX!
endlocal
)
)
endlocal
Преимущество этого метода состоит в том, что длина строк поиска больше не ограничена 127 символами, а 254 символами минус 1 для каждого встречающегося вышеупомянутого метасимвола, применяя для findstr
версий после Windows XP.
Вот еще один обходной путь, использующий поиск без учета регистра с findstr
на первом месте, а затем пост-фильтрация результата с помощью сравнения с учетом регистра:
echo ffffaaa|findstr /L /I "ffffaaa faffaffddd"|cmd /V /C set /P STR=""^&if @^^!STR^^!==@^^!STR:ffffaaa=ffffaaa^^! (echo(^^!STR^^!) else if @^^!STR^^!==@^^!STR:faffaffddd=faffaffddd^^! (echo(^^!STR^^!)
Восклицательные знаки с двойным экранированием гарантируют, что переменная STR
раскрывается в явно вызванном экземпляре cmd
, даже если в экземпляре cmd
хоста включено отложенное расширение.
Кстати, из-за того, что я называю недостатком дизайна, поиск с использованием литеральных строк, использующих findstr
, никогда не будет работать надежно, если они содержат обратную косую черту, поскольку они все равно могут использоваться для экранирования после метасимволов, хотя и не обязательно ; например, строка поиска \.
фактически соответствует .
; чтобы действительно соответствовать \.
буквально, необходимо указать строку поиска \\.
. Я не понимаю, почему метасимволы все еще распознаются при выполнении буквального поиска, это не то, что я называю буквальным.