10

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

echo ffffaaa|findstr /l "ffffaaa faffaffddd"

为什么?

4

2 回答 2

15

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

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

我已经进行了许多实验,似乎必须满足以下所有条件才能发生故障:

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

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

如何指定搜索字符串并不重要。使用多个/C:"search"选项以及使用选项可实现相同的错误结果/G:file

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

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

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

  • 如果您正在使用该/V选项,则使用多个管道 FINDSTR 命令,每个命令带有一个搜索字符串,而不是一个 FINDSTR 命令和多个搜索。如果您有很多要使用该/G:file选项的搜索字符串,这也可能是一个问题。

我讨厌这个虫子!!!!

注意 - 请参阅Windows FINDSTR 命令有哪些未记录的功能和限制?获取 FINDSTR 特质的完整列表。

于 2012-01-19T05:05:27.560 回答
1

我不知道为什么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"

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

字符<>被排除在转义之外,以避免与单词边界发生冲突,单词边界分别由\<\>出现在搜索字符串的开头和结尾表示。

由于正则表达式对于 Windows XP 之前的版本限制为 254 个字符findstr(与文字字符串相反,后者限制为 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,对于每个出现的上述元字符,适用于findstrWindows 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一旦包含反斜杠就永远不会可靠地工作,因为尽管没有必要,但仍可能会消耗这些反斜杠来转义后面的元字符;例如,搜索字符串\.实际匹配.;要真正按字面匹配\.,您必须指定搜索字符串\\.。我不明白为什么在进行文字搜索时仍然可以识别元字符,这不是我所说的文字。

于 2017-06-04T22:02:24.327 回答