¿Por qué este ejemplo de FINDSTR con múltiples cadenas de búsqueda literales no encuentra una coincidencia?

El siguiente ejemplo de FINDSTR no puede encontrar una coincidencia.

echo ffffaaa|findstr /l "ffffaaa faffaffddd" 

¿Por qué?

Aparentemente, este es un error FINDSTR desde hace mucho tiempo. Creo que puede ser un error paralizante, dependiendo de las circunstancias.

Confirmé que el comando falla en dos máquinas diferentes de Vista, una máquina con Windows 7 y una máquina con XP. Encontré este findstr – roto ??? enlace que informa que una búsqueda similar falla en Windows Server 2003, pero tiene éxito en Windows 2000.

He realizado varios experimentos y parece que se deben cumplir todas las condiciones siguientes para el potencial de una falla:

  • La búsqueda usa múltiples cadenas de búsqueda literales
  • Las cadenas de búsqueda son de diferentes longitudes
  • Una cadena de búsqueda corta tiene cierta cantidad de superposición con una cadena de búsqueda más larga
  • La búsqueda es sensible a mayúsculas y minúsculas (opción no /I )

En cada falla que he visto, siempre falla una de las cadenas de búsqueda más cortas.

No importa cómo se especifiquen las cadenas de búsqueda. El mismo resultado erróneo se logra utilizando múltiples /C:"search" opciones de /C:"search" y también con la opción /G:file .

Las únicas 3 soluciones alternativas que he podido encontrar son:

  • Use la opción /I si no le importa el caso. Obviamente, esto podría no satisfacer tus necesidades.

  • Use la opción de expresión regular /R Pero si lo hace, debe asegurarse de que no haya metacaracteres en la búsqueda para que coincida con el resultado esperado de una búsqueda literal. Esto también puede ser problemático.

  • Si está utilizando la opción /V , utilice múltiples comandos FINDSTR canalizados con una cadena de búsqueda cada uno en lugar de un FINDSTR con múltiples búsquedas. Esto también puede ser un problema si tiene muchas cadenas de búsqueda para las cuales desea usar la opción /G:file .

¡Odio este error!

Nota : consulte ¿Cuáles son las características y limitaciones no documentadas del comando FINDSTR de Windows? para obtener una lista completa de las idiosincrasias de FINDSTR.

No puedo decir por qué findstr puede fallar con múltiples cadenas literales. Sin embargo, puedo proporcionar un método para evitar ese molesto error.

Dado que las cadenas de búsqueda literales se enumeran en un archivo de texto llamado search_strings.txt …:

 ffffaaa faffaffddd 

…, puedes convertirlo a expresiones regulares insertando una barra invertida delante de cada carácter:

 @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 

Luego use el archivo convertido regular_expressions.txt …:

 \f\f\f\f\a\a\a \f\a\f\f\a\f\f\d\d\d 

… para hacer una búsqueda de expresiones regulares, que parece funcionar bien también con múltiples cadenas de búsqueda:

 echo ffffaaa| findstr /R /G:"regular_expressions.txt" 

Las barras diagonales anteriores simplemente escapan a todos los caracteres, incluidos los que tienen un significado particular en las búsquedas de expresiones regulares.

Los caracteres < y > están excluidos de ser escapados para evitar conflictos con los límites de las palabras, que fueron expresados ​​por \< y \> cuando aparecen al principio y al final de una cadena de búsqueda, respectivamente.

Como las expresiones regulares están limitadas a 254 caracteres para findstr versiones de findstr anteriores a Windows XP (opuestas a las cadenas literales, que están limitadas a 511 caracteres), la longitud de las cadenas de búsqueda originales está limitada a 127 caracteres, porque cada carácter se expresa con dos caracteres debido al escape


Aquí hay un enfoque alternativo que solo escapa a los metacaracteres . , * , ^ , $ , [ , ] , \ , " :

 @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 

La ventaja de este método es que la longitud de las cadenas de búsqueda ya no está limitada a 127 caracteres, sino a 254 caracteres menos 1 por cada metacaraciente antes mencionado, y se aplica a findstr versiones de findstr anteriores a Windows XP.


Aquí hay otra findstr , al usar una búsqueda que no distingue entre mayúsculas y minúsculas con findstr en primer lugar, y luego filtrar el resultado por medio de comparaciones entre mayúsculas y minúsculas:

 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^^!) 

Los signos de exclamación de doble escape aseguran que la variable STR se expanda en la instancia de cmd explícitamente invocada, incluso en el caso de que la expansión retrasada esté habilitada en la instancia de cmd alojamiento.


Por cierto, debido a lo que yo llamo una falla de diseño, las búsquedas con cadenas literales usando findstr nunca funcionan de manera confiable tan pronto como contienen barras invertidas, porque aún pueden consumirse para escapar de los siguientes metacaracteres, aunque no son necesarios; por ejemplo, la cadena de búsqueda \. en realidad coincide . ; para realmente combinar \. literalmente, debe especificar la cadena de búsqueda \\. . No entiendo por qué los metacaracteres todavía se reconocen al hacer búsquedas literales, eso no es lo que llamo literal.