Pourquoi cet exemple FINDSTR avec plusieurs chaînes de recherche littérales ne trouve-t-il pas une correspondance?

l'exemple FINDSTR suivant ne trouve pas de correspondance.

echo ffffaaa|findstr /l "ffffaaa faffaffddd"

pourquoi?

8
demandé sur dbenham 2012-01-19 09:01:57

2 réponses

apparemment, il s'agit D'un bug FINDSTR de longue date. Je pense que ça peut être un bogue paralysant, selon les circonstances.

j'ai confirmé que la commande échoue sur deux machines Vista différentes, une machine Windows 7, et une machine XP. J'ai trouvé ce cassé ??? lien qui signale une recherche similaire échoue sur Windows Server 2003, mais il réussit sur Windows 2000.

j'ai fait un certain nombre d'expériences et il semble toutes les conditions suivantes doivent être remplies pour qu'une défaillance soit possible:

  • la recherche utilise plusieurs chaînes de recherche littérale
  • Les chaînes de recherche sont de longueurs différentes
  • une chaîne de recherche courte a un certain degré de chevauchement avec une chaîne de recherche plus longue
  • la recherche est sensible à la casse (pas d'option /I )

dans chaque échec que j'ai vu, c'est toujours l'une des chaînes de recherche les plus courtes qui échoue.

peu importe comment les chaînes de recherche sont spécifiées. Le même résultat défectueux est obtenu en utilisant plusieurs options /C:"search" et aussi avec l'option /G:file .

les 3 seules solutions de rechange que j'ai pu trouver sont:

  • utilisez l'option /I si vous ne vous souciez pas de case. Évidemment, cela pourrait ne pas répondre à vos besoin.

  • utilisez l'option d'expression régulière /R . Mais si vous le faites, vous devez vous assurer que vous échappez à tous les méta-caractères dans la recherche afin qu'ils correspondent au résultat attendu d'une recherche littérale. Cela peut être problématique.

  • si vous utilisez l'option /V , utilisez plusieurs commandes findstr avec une chaîne de recherche chacune au lieu d'une FINDSTR avec plusieurs rechercher. Ce peut également être un problème si vous avez beaucoup de chaînes de recherche pour lequel vous souhaitez utiliser le /G:file option.

je déteste ce bug!!!!

Note - voir quelles sont les caractéristiques et les limites non documentées de la commande Windows FINDSTR? pour une liste complète des FINDSTR les particularités.

13
répondu dbenham 2017-05-23 12:02:39

je ne peux pas dire pourquoi findstr peut échouer avec plusieurs chaînes littérales. Cependant, je peux fournir une méthode pour contourner ce bug gênant.

étant donné que les chaînes de recherche littérales sont listées dans un fichier texte appelé search_strings.txt ...:

ffffaaa
faffaffddd

..., vous pouvez le convertir en expressions régulières en insérant un antislash devant chaque caractère:

@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

Puis utilisez le fichier converti regular_expressions.txt ...:

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

... pour faire une recherche d'expression régulière, qui semble fonctionner très bien aussi avec des chaînes de recherche multiples:

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

les antislashs précédents échappent tout simplement à tout caractère, y compris ceux qui ont une signification particulière dans les recherches d'expressions régulières.

les caractères < et > sont exclus échappée afin d'éviter les conflits avec les limites des mots, qui ont été exprimées par \< et \> lorsqu'elles apparaissent respectivement au début et à la fin d'une chaîne de recherche.

étant donné que les expressions régulières sont limitées à 254 caractères pour les versions findstr au-delà de Windows XP (par opposition aux chaînes littérales, qui sont limitées à 511 caractères), la longueur des chaînes de recherche originales est limitée à 127 caractères, car chacun de ces caractères est exprimé par deux caractères en raison de l'évasion.


Voici une approche alternative qui n'échappe qu'aux méta-caractères . , * , ^ , $ , [ , ] , \ , " :

@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

L'avantage de cette méthode est que la longueur des chaînes de recherche n'est plus limité à 127 caractères mais à 254 caractères moins de 1 pour chaque en cours méta-caractère susmentionné, application pour les versions findstr au-delà de Windows XP.


Voici une autre solution, en utilisant une recherche non sensible à la casse avec findstr en premier lieu, puis en post-filtrant le résultat par des comparaisons sensibles à la casse:

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

les points d'exclamation échappés en double assurent que la variable STR est étendue dans l'instance explicitement invoquée cmd même dans l'extension en cas de retard est activée dans l'instance d'hébergement cmd .


soit dit en passant, en raison de ce que j'appelle un défaut de conception, les recherches avec des chaînes littérales à l'aide de findstr ne fonctionnent jamais de manière fiable dès qu'ils contiennent des antislashs, parce que ceux-ci peuvent encore être consommés pour échapper à la suite de méta-caractères, bien que ce ne soit pas nécessaire; par exemple, la chaîne de recherche \. correspond en fait . ; pour vraiment correspondre \. littéralement, vous devez spécifier la chaîne de recherche \. . Je ne comprends pas pourquoi les méta-caractères sont encore reconnus lors de recherches littérales, ce n'est pas ce que j'appelle littéral.

1
répondu aschipfl 2017-07-10 07:17:08