为什么这个带有多个文字searchstring的FINDSTR例子找不到匹配?

以下FINDSTR示例未能find匹配项。

echo ffffaaa|findstr /l "ffffaaa faffaffddd" 

为什么?

这是一个长期存在的FINDSTR错误。 我认为这可能是一个严重的错误,取决于具体情况。

我已经确认这个命令在两台不同的Vista机器,一台Windows 7机器和一台XP机器上都失败了。 我发现这findstr – 破? 链接报告类似的search在Windows Server 2003上失败,但在Windows 2000上成功。

我已经做了大量的实验,看起来以下所有条件都必须满足潜在的失败:

  • search使用多个文字searchstring
  • searchstring具有不同的长度
  • 短searchstring与较长的searchstring有一些重叠
  • search区分大小写(无/I选项)

在我看到的每一次失败中,它总是失败的较短searchstring之一。

如何指定searchstring并不重要。 使用多个/C:"search"选项以及/G:file选项也可以获得相同的错误结果。

我已经能够提出的唯一的三个解决方法是:

  • 如果您不关心案例,请使用/I选项。 显然这可能不符合你的需求。

  • 使用/R正则expression式选项。 但是,如果你这样做,那么你必须确保你在search中转义任何元字符,以便它符合文字search的预期结果。 这也可能是有问题的。

  • 如果您使用的是/V选项,则使用多个pipe道FINDSTR命令,每个searchstring代替一个FINDSTR,并使用多个search。 如果您想要使用/G:file选项的searchstring很多,这也可能是一个问题。

我讨厌这个bug!

– 请参阅Windows FINDSTR命令的未logging的function和限制是什么? 为FINDSTR特质的一个全面的名单。

我不知道为什么findstr可能会失败,多个string。 不过,我可以提供一个方法来解决这个烦人的bug。

鉴于文字searchstring列在名为search_strings.txt …的文本文件中:

 ffffaaa faffaffddd 

…,可以通过在每个单个字符前面插入一个反斜杠来将其转换为正则expression式:

 @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 

…做一个正则expression式search,这似乎也适用于多个searchstring:

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

前面的反斜杠只是转义每个字符,包括那些在正则expression式search中具有特定含义的字符。

字符<>不能被转义,以避免与\<\>在出现在searchstring开头和结尾处的字边界冲突。

由于对于Windows XP以上的findstr版本,正则expression式的长度限制为254个字符(与文字string限制为511个字符相对),原始searchstring的长度限制为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 

这种方法的优点是searchstring的长度不再限制为127个字符,而是每个前面提到的元字符减去254个字符减1,适用于Windows XP以上的findstr版本。


下面是另一个解决方法,首先使用findstr进行不区分大小写的search,然后通过区分大小写的比较对结果进行后置过滤:

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

即使在托pipecmd实例中启用延迟扩展的情况下,双转义感叹号也确保variablesSTR在显式调用的cmd实例中展开。


顺便说一句,由于我称之为devise缺陷,只要包含反斜杠,使用findstrstringsearch就不会可靠地工作,因为尽pipe不是必要的,但它们仍然可以被用来逃避元字符。 例如,searchstring\. 实际上匹配. ; 真正匹配\. 从字面上看,您必须指定searchstring\\. 。 我不明白为什么元字符在进行文字search时仍然可以识别,这不是我所说的字面意思。