为什么这个带有多个文字搜索字符串的FINDSTR示例找不到匹配?

时间:2012-01-19 05:01:58

标签: batch-file cmd findstr

以下FINDSTR示例无法找到匹配项。

echo ffffaaa|findstr /l "ffffaaa faffaffddd"

为什么?

2 个答案:

答案 0 :(得分:13)

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

我已确认该命令在两台不同的Vista计算机,Windows 7计算机和XP计算机上失败。 我发现此findstr - broken ???链接报告类似的搜索在Windows Server 2003上失败,但它在Windows 2000上成功。

我做了很多实验,似乎必须满足以下所有条件才能发生失败:

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

在我看到的每一次失败中,它总是失败的较短搜索字符串之一。

如何指定搜索字符串无关紧要。使用多个/C:"search"选项以及/G:file选项也可以获得相同的错误结果。

我能够提出的唯一3个解决方法是:

  • 如果您不关心案例,请使用/I选项。显然这可能无法满足您的需求。

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

  • 如果您使用/V选项,则使用多个管道FINDSTR命令,每个命令包含一个搜索字符串,而不是一个具有多个搜索的FINDSTR。如果您有大量要使用/G:file选项的搜索字符串,这也可能会出现问题。

我讨厌这个错误!!!!

注意 - 有关FINDSTR特性的完整列表,请参阅What are the undocumented features and limitations of the Windows FINDSTR command?

答案 1 :(得分:1)

我不知道为什么findstr可能会因多个文字字符串而失败。但是,我可以提供一种解决这个烦人的bug的方法。

鉴于文字搜索字符串列在名为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"

前面的反斜杠只是逃避每个字符,包括那些在正则表达式搜索中具有特定含义的字符。

字符<>不会被转义,以避免与字边界发生冲突,\<\>在开头出现时表示并分别在搜索字符串的末尾。

由于正常表达式限制为通过Windows XP的findstr版本的254个字符(与文字字符串相对,限制为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,申请通过Windows XP的findstr版本。< / p>

这是另一种解决方法,首先使用不区分大小写的搜索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的文字字符串搜索一旦包含反斜杠就永远无法可靠地工作,因为这样可能仍然会被消耗掉以跟随元字符,尽管不必要;例如,搜索字符串\.实际上匹配.;要从字面上真正匹配\.,您必须指定搜索字符串\\.。我不明白为什么在进行文字搜索时仍然可以识别元字符,这不是我所谓的文字。