Windows FINDSTR命令的未记录的特性和限制是什么?

Windows FINDSTR命令的文档记录非常糟糕。通过FINDSTR /?HELP FINDSTR可以获得非常基本的命令行帮助,但遗憾的是,这是不够的。在https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/findstr上有更多的在线文档。

文档中甚至没有提到FINDSTR的许多特性和限制。如果没有事先的知识和/或仔细的实验,也无法预测它们。

问题是- 没有记录的FINDSTR特性和限制是什么?

这个问题的目的是提供许多未记录的特性的一站式存储库,以便:

A)开发人员可以充分利用现有的功能。

B)开发人员不会浪费时间去思考为什么有些东西看起来应该不能工作。

在回复之前,请确保您了解现有的文档。如果信息包含在HELP中,那么它就不属于这里。

这里也不是展示FINDSTR有趣用法的地方。如果一个有逻辑的人可以根据文档预测FINDSTR的特定用法的行为,那么它就不属于这里。

同样,如果一个有逻辑的人可以根据任何现有答案中包含的信息预测特定用法的行为,那么它也不属于这里。

140374 次浏览
< p > <强>序言< / >强
这个答案中的大部分信息都是基于在Vista机器上运行的实验而收集的。除非特别说明,我没有确认该信息是否适用于其他Windows版本

< p > 中输出
文档从未费心解释FINDSTR的输出。它暗示了打印匹配的行,但仅此而已

匹配行输出格式如下:

< >强文件名:lineNumber: lineOffset:文本< / >强

在哪里

< >强文件名:< / >强 =包含匹配行的文件名。如果请求显式地针对单个文件,或者搜索管道输入或重定向输入,则不会打印文件名。打印时,fileName将始终包含所提供的任何路径信息。如果使用/S选项,则会添加额外的路径信息。打印的路径总是相对于提供的路径,如果没有提供,则相对于当前目录。

注意:当使用非标准(且文档记录不佳)通配符 <>搜索多个文件时,可以避免使用文件名前缀。这些通配符工作的确切规则可以在在这里中找到。最后,你可以看看这个非标准通配符如何与FINDSTR一起工作的示例

< >强lineNumber: < / >强 =匹配行的行号,表示为十进制值,1表示输入的第一行。仅在指定/N选项时打印。

< >强lineOffset: < / >强 =匹配行开始的十进制字节偏移量,0表示第一行的第一个字符。仅在指定/O选项时打印。这是该行内匹配的偏移量。它是从文件开始到行开始的字节数。

<强>文本< / >强 =匹配行的二进制表示形式,包括任意<CR>和/或& lt; LF>。二进制输出中没有遗漏任何内容,因此这个匹配所有行的示例将生成原始文件的精确二进制副本。

FINDSTR "^" FILE >FILE_COPY

/A选项只设置fileName:、lineNumber:和lineOffset:输出的颜色。匹配行的文本总是以当前控制台的颜色输出。/A选项仅在输出直接显示到控制台时有效。如果输出被重定向到文件或管道,/A选项将不起作用。有关输出重定向到CON时的错误行为的描述,请参阅Aacini的回答2018-08-18编辑

< p > 大多数控制字符和许多扩展ASCII字符在XP上显示为点
XP上的FINDSTR将来自匹配行的大多数不可打印控制字符显示为屏幕上的点(句号)。以下控制字符是例外;它们显示为自身:0x09标签,0x0A换行,0x0B垂直标签,0x0C表单换行,0x0D回车

XP FINDSTR还将一些扩展的ASCII字符转换为点。在XP上显示为点的扩展ASCII字符与在命令行上提供时转换的字符相同。参见本文后面的命令行参数的字符限制-扩展ASCII转换部分

如果输出是管道输出、重定向到文件或在FOR IN()子句中,则控制字符和扩展ASCII不会在XP上转换为点。

Vista和Windows 7总是显示所有字符本身,而不是点。

返回码(ERRORLEVEL)

    <李> 0(成功)
    • 在至少一个文件的至少一行中找到匹配项。
    <李> 1(失败)
    • 在任何文件的任何一行都没有找到匹配。
    • /A:xx选项指定的颜色无效
    <李> 2(错误)
    • 不兼容的选项/L/R都指定了
    • /A:/F:/C:/D:/G:后缺少参数
    • /F:file/G:file指定的文件未找到
    <李> 255(错误)
< p > 要搜索的数据来源 (根据Windows 7测试更新)
Findstr只能从以下来源之一搜索数据:

  • 文件名指定为参数和/或使用/F:file选项。

  • stdin通过重定向findstr "searchString" <file

  • 来自管道type file | findstr "searchString"的数据流

参数/选项优先于重定向,重定向优先于管道数据。

文件名参数和/F:file可以组合。可以使用多个文件名参数。如果指定了多个/F:file选项,则只使用最后一个选项。文件名参数中允许通配符,但/F:file所指向的文件中不允许通配符。

< p > 搜索字符串的来源 (根据Windows 7测试更新)
/G:file/C:string选项可以组合。可以指定多个/C:string选项。如果指定了多个/G:file选项,则只使用最后一个选项。如果使用/G:file/C:string,则所有非选项参数都假定为要搜索的文件。如果既不使用/G:file也不使用/C:string,则第一个非选项参数将被视为空格分隔的搜索词列表 < p > 当使用/F:FILE选项时,文件名不能在文件中引用。
文件名可能包含空格和其他特殊字符。大多数命令要求这样的文件名加引号。但是FINDSTR /F:files.txt选项要求files.txt中的文件名不能被引用。

.

.

.

. < p > 短小的8.3文件名会破坏__ABC0和/S选项
与所有Windows命令一样,FINDSTR在查找要搜索的文件时,将尝试同时匹配长名称和短8.3名称。假设当前文件夹包含以下非空文件:

b1.txt
b.txt2
c.txt

下面的命令将成功找到所有3个文件:

findstr /m "^" *.txt

b.txt2匹配,因为对应的短名称B9F64~1.TXT匹配。这与所有其他Windows命令的行为一致。

但是/D/S选项的错误导致以下命令只能找到b1.txt

findstr /m /d:. "^" *.txt
findstr /m /s "^" *.txt

该错误会阻止找到b.txt2,以及同一目录中所有在b.txt2之后排序的文件名。找到之前排序的其他文件,如a.txt。稍后排序的其他文件,如d.txt,一旦bug被触发就会丢失。

搜索的每个目录都是独立处理的。例如,/S选项在未能在父文件夹中找到文件后将成功地开始在子文件夹中搜索,但一旦错误导致子文件夹中缺少一个短文件名,那么该子文件夹中的所有后续文件也将丢失。

如果在禁用了NTFS 8.3名称生成的机器上创建了相同的文件名,则该命令可以正常工作。当然b.txt2不会被找到,但是c.txt会被正确找到。

并不是所有的短名称都会触发该错误。我所见过的所有有漏洞的行为实例都涉及扩展名长度超过3个字符,其8.3短名称与不需要8.3名称的正常名称开头相同。

该漏洞已在XP、Vista和Windows 7上得到确认。

< p > 不可打印字符和/P选项
/P选项导致FINDSTR跳过任何包含以下任何十进制字节代码的文件 0-7, 14-25, 27-31.

换句话说,/P选项将只跳过包含不可打印控制字符的文件。控制字符是小于或等于31的代码(0x1F)。FINDSTR将以下控制字符视为可打印的:

 8  0x08  backspace
9  0x09  horizontal tab
10  0x0A  line feed
11  0x0B  vertical tab
12  0x0C  form feed
13  0x0D  carriage return
26  0x1A  substitute (end of text)

所有其他控制字符都被视为不可打印字符,它们的存在会导致/P选项跳过文件。

< p > 管道和重定向输入可能会附加<CR><LF>
如果输入是通过管道输入的,并且流的最后一个字符不是<LF>,那么FINDSTR将自动将<CR><LF>附加到输入。XP、Vista和Windows 7系统已经证实了这一点。(我曾经认为Windows管道负责修改输入,但我后来发现FINDSTR实际上正在进行修改。) < / p >

在Vista上重定向输入也是如此。如果用作重定向输入的文件的最后一个字符不是<LF>,则FINDSTR将自动将<CR><LF>附加到输入。然而,XP和Windows 7不改变重定向输入。

< p > 如果重定向输入不以<LF>结尾,FINDSTR挂起在XP和Windows 7上
这是一个令人讨厌的“特征”;XP和Windows 7操作系统。如果用作重定向输入的文件的最后一个字符不以<LF>结尾,则FINDSTR将在到达重定向文件的结尾时无限期挂起 < p > 如果管道数据的最后一行由单个字符组成,则可以忽略它
如果输入是通过管道输入的,并且最后一行由单个字符组成,后面没有<LF>,则FINDSTR完全忽略最后一行

示例-第一个带有单个字符且没有<LF>的命令无法匹配,但第二个带有两个字符的命令可以正常工作,第三个命令具有一个带有结束换行符的字符。

> set /p "=x" <nul | findstr "^"


> set /p "=xx" <nul | findstr "^"
xx


> echo x| findstr "^"
x

DosTips用户Sponge Belly在新的findstr错误报告。在XP, Windows 7和Windows 8上确认。还没听说过Vista。(我不再需要测试Vista了)。

< p > 选项的语法
选项字母不区分大小写,因此/i/I是等效的 选项可以以/-作为前缀 选项可以在单个/-之后连接。但是,连接后的选项列表中最多只能包含一个多字符选项,例如OFF或F:,且该多字符选项必须位于列表的最后

以下是对包含"hello"和“;goodbye"任意顺序

  • < p > /i /r /c:"hello.*goodbye" /c:"goodbye.*hello"

  • < p > -i -r -c:"hello.*goodbye" /c:"goodbye.*hello"

  • < p > /irc:"hello.*goodbye" /c:"goodbye.*hello"

期权也可以报价。所以/i-i"/i""-i"都是等价的。同样地,/c:string"/c":string"/c:"string"/c:string"都是等价的。

如果搜索字符串以/-文字开头,则必须使用/C/G选项。感谢斯蒂芬在注释中报告这一点(已删除)。

如果使用了/c:string/g:file选项,则如果文件名参数以-开头,则命令将失败,即使使用引号。这是因为没有搜索字符串参数,因此文件名参数被视为一个选项。最简单的解决方法是在file参数前加上。反斜杠,如

findstr /c:"searchString" ".\-fileName.txt"
< p > 搜索字符串长度限制
在Vista上,单个搜索字符串允许的最大长度是511字节。如果任何搜索字符串超过511,则结果是一个带有ERRORLEVEL 2的FINDSTR: Search string too long.错误

使用正则表达式进行搜索时,最大搜索字符串长度为254。长度在255到511之间的正则表达式将导致ERRORLEVEL 2的FINDSTR: Out of memory错误。正则表达式长度>511会导致FINDSTR: Search string too long.错误。

在Windows XP上,搜索字符串的长度明显更短。Findstr错误:“搜索字符串太长”:如何在“for”中提取和匹配子字符串;循环? 对于文字和正则表达式搜索,XP限制都是127字节 < p > 线长限制
作为命令行参数或通过/F:FILE选项指定的文件没有已知的行长限制。成功搜索到一个128MB的文件,该文件不包含单个<LF>.

管道数据和重定向输入每行限制为8191字节。这个限制是一个“特征”;中。它不是管道或重定向所固有的。使用重定向stdin或管道输入的FINDSTR将永远不会匹配任何>=8k字节的行。Lines >= 8k生成一个错误消息到stderr,但是如果在至少一个文件的至少一行中找到了搜索字符串,ERRORLEVEL仍然为0。

< p > 默认搜索类型:文字vs正则表达式
/C:"string" -默认是/L文字。将/L选项与/C显式组合:"string"

"string argument" -默认值取决于第一个搜索字符串的内容。(记住<space>用于分隔搜索字符串。)如果第一个搜索字符串是一个有效的正则表达式,包含至少一个未转义的元字符,那么所有搜索字符串都被视为正则表达式。否则,所有搜索字符串都被视为字面量。例如,"51.4 200"将被视为两个正则表达式,因为第一个字符串包含一个未转义的点,而"200 51.4"将被视为两个字面量,因为第一个字符串不包含任何元字符。

/G:file -默认值取决于文件中第一个非空行的内容。如果第一个搜索字符串是一个有效的正则表达式,包含至少一个未转义的元字符,那么所有搜索字符串都被视为正则表达式。否则,所有搜索字符串都被视为字面量。

建议-在使用"string argument"/G:file时,始终显式地指定/L文字选项或/R正则表达式选项。

指定多个文字搜索字符串会给出不可靠的结果

下面的简单FINDSTR示例无法找到匹配,尽管它应该找到匹配。

echo ffffaaa|findstr /l "ffffaaa faffaffddd"

此错误已在Windows Server 2003、Windows XP、Vista和Windows 7上确认。

根据实验,如果满足以下所有条件,FINDSTR可能会失败:

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

在我所见过的每一次失败中,失败的总是一个较短的搜索字符串。

更多信息见为什么这个带有多个文字搜索字符串的FINDSTR示例没有找到匹配?

< p > 命令行参数中的引号和反斜杠
注意: < / em > 用户MC ND的评论反映了这个部分的实际复杂得可怕的规则。这里涉及到3个不同的解析阶段:

  • 首先cmd.exe可能需要一些引号转义为^"(实际上与FINDSTR无关)
  • 接下来FINDSTR使用pre 2008 MS C/ c++参数解析器,其中有特殊的规则"和\
  • 参数解析器完成后,FINDSTR还会将后面跟字母数字字符的\视为文字,而将后面跟非字母数字字符的\视为转义字符

这个突出显示的部分的其余部分不是100%正确的。它可以作为许多情况下的指南,但要全面理解以上规则是必需的。

在命令行搜索字符串中转义引号
命令行搜索字符串中的引号必须使用反斜杠进行转义 \"。这对于文字和正则表达式搜索字符串都是正确的。这 XP, Vista和Windows 7的信息已被确认 注意:CMD.EXE解析器可能还需要转义引号,但这与FINDSTR无关。例如,搜索a 你可以使用单引号:

FINDSTR \^" file && echo found || echo not found

在命令行文本搜索字符串中转义反斜杠
字面搜索字符串中的反斜杠通常可以表示为 \\\。它们通常是等价的。(可能有异常 在Vista的情况下,反斜杠必须总是转义,但我没有 .

..

.

但也有一些特殊情况:

当搜索连续的反斜杠时,除最后一个必须之外的所有必须都是 逃脱了。

.最后一个反斜杠可以选择转义
  • \\可以被编码为\\\\\\\
  • \\\可以被编码为\\\\\\\\\\\
在引号前搜索一个或多个反斜杠是很奇怪的。逻辑 会建议引用必须转义,和每个领导 反斜杠需要转义,但这不起作用!相反, 每个开头的反斜杠必须被双转义,并且引号 正常转义:

  • \"必须被编码为\\\\\"
  • \\"必须被编码为\\\\\\\\\"

如前所述,对于CMD解析器,一个或多个转义引号也可能需要使用^进行转义

本章节内容已在XP和Windows 7操作系统下确认。

在命令行正则表达式搜索字符串中转义反斜杠

    正则表达式中的反斜杠必须像\\\\那样进行双转义,或者像\\\\那样在字符类集中进行单转义 [\\] < / p >
  • XP和Windows 7:正则表达式中的反斜杠总是可以表示为[\\]。它通常可以表示为\\。但这从来没有 如果反斜杠在转义引号之前,则有效 转义引号前的一个或多个反斜杠必须为 double转义,否则编码为[\\]

    • \"可以被编码为\\\\\"[\\]\"
    • \\"可以被编码为\\\\\\\\\"[\\][\\]\"\\[\\]\"
< p > 转义/G:FILE文本搜索字符串中的引号和反斜杠
由/G:file指定的文本搜索字符串文件中的独立引号和反斜杠不需要转义,但可以进行转义

"\"是等价的。

\\\是等价的。

如果目的是查找\\,那么至少必须转义前导反斜杠。\\\\\\\都可以工作。

如果目的是寻找",那么至少前导反斜杠必须转义。\\"\\\"都可以工作。

< p > 转义/G:FILE正则表达式搜索字符串中的引号和反斜杠
这是转义序列按照文档的预期工作的一种情况。Quote不是正则表达式元字符,因此不需要转义(但可以转义)。反斜杠是一个正则表达式元字符,所以必须转义 < p > 命令行参数的字符限制。扩展ASCII转换
空字符(0x00)不能出现在命令行的任何字符串中。任何其他单字节字符都可以出现在字符串(0x01 - 0xFF)中。但是,FINDSTR将在命令行参数中找到的许多扩展ASCII字符转换为其他字符。这在两个方面有重大影响:

  1. 如果在命令行上使用扩展ASCII字符作为搜索字符串,许多扩展ASCII字符将不匹配自己。对于文字搜索和正则表达式搜索,这种限制是相同的。如果搜索字符串必须包含扩展的ASCII,则应该使用/G:FILE选项。

  2. FINDSTR如果文件名包含扩展ASCII字符,并且在命令行中指定了文件名,则可能无法找到文件。如果要搜索的文件名称中包含扩展ASCII,则应该使用/F:FILE选项。

下面是FINDSTR对命令行字符串执行的扩展ASCII字符转换的完整列表。每个字符都表示为十进制字节码值。第一个代码表示命令行上提供的字符,第二个代码表示它转换成的字符。注意:这个列表是在一台美国机器上编译的。我不知道其他语言对这个列表会有什么影响。

158 treated as 080     199 treated as 221     226 treated as 071
169 treated as 170     200 treated as 043     227 treated as 112
176 treated as 221     201 treated as 043     228 treated as 083
177 treated as 221     202 treated as 045     229 treated as 115
178 treated as 221     203 treated as 045     231 treated as 116
179 treated as 221     204 treated as 221     232 treated as 070
180 treated as 221     205 treated as 045     233 treated as 084
181 treated as 221     206 treated as 043     234 treated as 079
182 treated as 221     207 treated as 045     235 treated as 100
183 treated as 043     208 treated as 045     236 treated as 056
184 treated as 043     209 treated as 045     237 treated as 102
185 treated as 221     210 treated as 045     238 treated as 101
186 treated as 221     211 treated as 043     239 treated as 110
187 treated as 043     212 treated as 043     240 treated as 061
188 treated as 043     213 treated as 043     242 treated as 061
189 treated as 043     214 treated as 043     243 treated as 061
190 treated as 043     215 treated as 043     244 treated as 040
191 treated as 043     216 treated as 043     245 treated as 041
192 treated as 043     217 treated as 043     247 treated as 126
193 treated as 045     218 treated as 043     249 treated as 250
194 treated as 045     219 treated as 221     251 treated as 118
195 treated as 043     220 treated as 095     252 treated as 110
196 treated as 045     222 treated as 221     254 treated as 221
197 treated as 043     223 treated as 095
198 treated as 221     224 treated as 097

任何不在上面列表中的字符>0都被视为本身,包括<CR>和<LF>。包含像<CR><LF>这样的奇数字符最简单的方法是将它们放到一个环境变量中,并在命令行参数中使用延迟展开。

< p > 在/G:FILE和/F:FILE选项指定的文件中找到的字符串的字符限制
nul (0x00)字符可以出现在文件中,但它的功能类似于C字符串结束符。null字符之后的任何字符都被视为不同的字符串,就像它们在另一行一样

<CR><LF>字符被视为终止字符串的行终止符,不包含在字符串中。

所有其他单字节字符都被完美地包含在字符串中。

< p > 搜索Unicode文件
FINDSTR不能正确搜索大多数Unicode (UTF-16, UTF-16LE, UTF-16BE, UTF-32),因为它不能搜索空字节,而Unicode通常包含许多空字节

然而,TYPE命令将带有BOM的UTF-16LE转换为单字节字符集,因此像下面这样的命令将使用带有BOM的UTF-16LE。

type unicode.txt|findstr "search"

请注意,活动代码页不支持的Unicode码位将被转换为?字符。

只要您的搜索字符串只包含ASCII,就可以搜索UTF-8。但是,任何多字节UTF-8字符的控制台输出都是不正确的。但是如果您将输出重定向到一个文件,那么结果将被正确地编码为UTF-8。请注意,如果UTF-8文件包含一个BOM,那么该BOM将被视为第一行的一部分,这可能会抛出匹配一行开头的搜索。

如果您将搜索字符串放在UTF-8编码的搜索文件(不含BOM)中,并使用/G选项,则可以搜索多字节UTF-8字符。

< p > 行结束
FINDSTR在每个<LF>之后立即换行。<CR>对换行符没有影响

< p > 跨换行符搜索
正如预期的那样,.正则表达式元字符将不匹配<CR>或& lt; LF>。但是可以使用命令行搜索字符串跨换行符进行搜索。无论是<CR>和& lt; LF>字符必须显式匹配。如果找到多行匹配,则只打印匹配的第一行。FINDSTR然后翻回到源代码中的第二行,并重新开始搜索——类似于“向前看”。类型特征。< / p >

假设TEXT.TXT包含以下内容(可以是Unix或Windows样式)

A
A
A
B
A
A

然后这个脚本

@echo off
setlocal
::Define LF variable containing a linefeed (0x0A)
set LF=^




::Above 2 blank lines are critical - do not remove


::Define CR variable containing a carriage return (0x0D)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"


setlocal enableDelayedExpansion
::regex "!CR!*!LF!" will match both Unix and Windows style End-Of-Line
findstr /n /r /c:"A!CR!*!LF!A" TEST.TXT

给出这些结果

1:A
2:A
5:A

使用/G:FILE选项搜索跨换行符是不精确的,因为匹配<CR>或& lt; LF>是通过一个正则表达式字符类范围表达式来夹住EOL字符。

  • [<TAB>-<0x0B>]匹配<LF>,但它也匹配<TAB>和& lt; 0 x0b>

  • [<0x0C>-!]匹配<CR>,但它也匹配<0x0C>和!

注意——以上是正则字节流的符号表示,因为我不能图形化地表示这些字符。

下面第二部分继续回答

回答继续从上面的第1部分 -我已经遇到了30,000个字符的回答限制:-(

< p > 有限的正则表达式支持
FINDSTR对正则表达式的支持非常有限。如果HELP文档中没有,则表示不支持

除此之外,所支持的regex表达式是以完全非标准的方式实现的,因此结果可能与来自grep或perl等程序的预期结果不同。

< p > 正则表达式行位置锚^和$
^匹配输入流的开始以及紧跟在<LF>后面的任何位置。因为FINDSTR也在<LF>之后换行,一个简单的“^”正则表达式将始终匹配文件中的所有行,即使是二进制文件

$匹配紧接在<CR>之前的任何位置。这意味着包含$的正则表达式搜索字符串将永远不会匹配Unix风格文本文件中的任何行,也不会匹配Windows文本文件的最后一行,如果它缺少EOL标记<CR><LF>。

注意-如前所述,管道和重定向到FINDSTR的输入可能附加了不在源代码中的<CR><LF>。显然,这可能会影响使用$的正则表达式搜索。

任何包含^之前或$之后字符的搜索字符串将始终无法找到匹配。

< p > 位置选项/B /E /X
位置选项的工作原理与^$相同,除了它们也适用于文字搜索字符串

/B的功能与正则表达式搜索字符串开头的^相同。

/E函数与正则表达式搜索字符串末尾的$函数相同。

/X函数与正则表达式搜索字符串的开头和结尾都有^$相同。

< p > 正则表达式字边界
\<必须是正则表达式中的第一个项。如果正则表达式前面有其他字符,则正则表达式将不匹配任何字符。\<对应于输入的最开始,一行的开始(紧跟在<LF>后面的位置),或者紧跟在任何“非单词”字符后面的位置。下一个字符不需要是“word”字符

\>必须是正则表达式中的最后一项。如果正则表达式后面有其他字符,则它将不匹配任何字符。\>对应于输入的结束,紧接在<CR>之前的位置,或者紧接在任何“非单词”字符之前的位置。前面的字符不必是“word”字符。

下面是“非单词”字符的完整列表,用十进制字节代码表示。注意:这个列表是在一台美国机器上编译的。我不知道其他语言对这个列表会有什么影响。

001   028   063   179   204   230
002   029   064   180   205   231
003   030   091   181   206   232
004   031   092   182   207   233
005   032   093   183   208   234
006   033   094   184   209   235
007   034   096   185   210   236
008   035   123   186   211   237
009   036   124   187   212   238
011   037   125   188   213   239
012   038   126   189   214   240
014   039   127   190   215   241
015   040   155   191   216   242
016   041   156   192   217   243
017   042   157   193   218   244
018   043   158   194   219   245
019   044   168   195   220   246
020   045   169   196   221   247
021   046   170   197   222   248
022   047   173   198   223   249
023   058   174   199   224   250
024   059   175   200   226   251
025   060   176   201   227   254
026   061   177   202   228   255
027   062   178   203   229
< p > 正则表达式字符类别范围[x-y]
字符类别范围不能正常工作。请看这个问题:为什么findstr不能正确处理case(在某些情况下)?,以及这个答案:https://stackoverflow.com/a/8767815/1012053.

问题是FINDSTR不按字节码值(通常认为是ASCII码,但ASCII仅从0x00 - 0x7F定义)对字符进行排序。大多数regex实现将[A-Z]视为所有大写英文大写字母。但是FINDSTR使用大致对应于SORT工作方式的排序序列。所以[a - z]包括完整的英语字母,包括大写字母和小写字母(除了“a”),以及带变音符的非英语alpha字符。

下面是FINDSTR支持的所有字符的完整列表,按照FINDSTR用于建立正则表达式字符类范围的排序顺序进行排序。字符以十进制字节码值表示。如果使用代码页437查看字符,我认为排序顺序最有意义。注意:这个列表是在一台美国机器上编译的。我不知道其他语言对这个列表会有什么影响。

001
002
003
004
005
006
007
008
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
127
039
045
032
255
009
010
011
012
013
033
034
035
036
037
038
040
041
042
044
046
047
058
059
063
064
091
092
093
094
095
096
123
124
125
126
173
168
155
156
157
158
043
249
060
061
062
241
174
175
246
251
239
247
240
243
242
169
244
245
254
196
205
179
186
218
213
214
201
191
184
183
187
192
212
211
200
217
190
189
188
195
198
199
204
180
181
182
185
194
209
210
203
193
207
208
202
197
216
215
206
223
220
221
222
219
176
177
178
170
248
230
250
048
172
171
049
050
253
051
052
053
054
055
056
057
236
097
065
166
160
133
131
132
142
134
143
145
146
098
066
099
067
135
128
100
068
101
069
130
144
138
136
137
102
070
159
103
071
104
072
105
073
161
141
140
139
106
074
107
075
108
076
109
077
110
252
078
164
165
111
079
167
162
149
147
148
153
112
080
113
081
114
082
115
083
225
116
084
117
085
163
151
150
129
154
118
086
119
087
120
088
121
089
152
122
090
224
226
235
238
233
227
229
228
231
237
232
234
< p > 正则表达式字符类的期限限制和BUG
FINDSTR不仅在正则表达式中被限制为最多15个字符类术语,而且无法正确处理超出限制的尝试。使用16个或更多字符类术语将导致交互式Windows弹出窗口,声明"查找字符串(QGREP)实用程序遇到问题,需要关闭。给您带来不便,我们深表歉意。”消息文本根据Windows版本略有不同。下面是FINDSTR将失败的一个例子:

echo 01234567890123456|findstr [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]

DosTips用户Judago 在这里报告了此错误。在XP、Vista和Windows 7上已经得到确认。

< p > 如果Regex搜索包含字节码0xFF(十进制255),则会失败(并可能无限期挂起)
任何包含字节码0xFF(十进制255)的正则表达式搜索都将失败。如果直接包含字节码0xFF,或者隐式包含在字符类范围内,则失败。请记住,FINDSTR字符类范围不会根据字节码值对字符进行排序。字符<0xFF><space><tab>字符之间的排序序列中相对较早出现。因此,任何同时包含<space><tab>的字符类别范围都将失败

具体的行为根据Windows版本稍有不同。如果包含0xFF, Windows 7将无限期挂起。XP不会挂起,但它总是找不到匹配,并偶尔打印以下错误消息- “进程试图写入不存在的管道。”

我不能再使用Vista的机器,所以我不能在Vista上测试。

< p > Regex错误:__ABC0和[^anySet]可以匹配End-Of-File
正则表达式.元字符只能匹配除<CR><LF>之外的任何字符。如果文件中的最后一行不是以<CR><LF>结束,则允许它匹配End-Of-File。但是,.将不匹配空文件

例如,一个名为"test.txt"的文件包含一行x,不终止<CR><LF>,将匹配以下内容:

findstr /r x......... test.txt

这个bug已经在XP和Win7上得到确认。

负字符集似乎也是如此。像[^abc]这样的东西将匹配End-Of-File。像[abc]这样的正字符集似乎工作得很好。我只在Win7上测试过这个功能。

在搜索大文件时,findstr有时会意外挂起。

我还没有确认具体的条件和边界大小。我怀疑任何大于2GB的文件都可能存在风险。

我在这方面有过复杂的经历,所以这不仅仅是文件大小的问题。这看起来可能是如果重定向输入不以LF结尾,FINDSTR挂起在XP和Windows 7上的变体,但正如所演示的,当输入被重定向时,这个特殊的问题就会出现。

下面的命令行会话(Windows 7)演示了findstr在搜索3GB文件时如何挂起。

C:\Data\Temp\2014-04>echo 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890> T100B.txt


C:\Data\Temp\2014-04>for /L %i in (1,1,10) do @type T100B.txt >> T1KB.txt


C:\Data\Temp\2014-04>for /L %i in (1,1,1000) do @type T1KB.txt >> T1MB.txt


C:\Data\Temp\2014-04>for /L %i in (1,1,1000) do @type T1MB.txt >> T1GB.txt


C:\Data\Temp\2014-04>echo find this line>> T1GB.txt


C:\Data\Temp\2014-04>copy T1GB.txt + T1GB.txt + T1GB.txt T3GB.txt
T1GB.txt
T1GB.txt
T1GB.txt
1 file(s) copied.


C:\Data\Temp\2014-04>dir
Volume in drive C has no label.
Volume Serial Number is D2B2-FFDF


Directory of C:\Data\Temp\2014-04


2014/04/08  04:28 PM    <DIR>          .
2014/04/08  04:28 PM    <DIR>          ..
2014/04/08  04:22 PM               102 T100B.txt
2014/04/08  04:28 PM     1 020 000 016 T1GB.txt
2014/04/08  04:23 PM             1 020 T1KB.txt
2014/04/08  04:23 PM         1 020 000 T1MB.txt
2014/04/08  04:29 PM     3 060 000 049 T3GB.txt
5 File(s)  4 081 021 187 bytes
2 Dir(s)  51 881 050 112 bytes free
C:\Data\Temp\2014-04>rem Findstr on the 1GB file does not hang


C:\Data\Temp\2014-04>findstr "this" T1GB.txt
find this line


C:\Data\Temp\2014-04>rem On the 3GB file, findstr hangs and must be aborted... even though it clearly reaches end of file


C:\Data\Temp\2014-04>findstr "this" T3GB.txt
find this line
find this line
find this line
^C
C:\Data\Temp\2014-04>

注意,我已经在十六进制编辑器中验证了所有行都以CRLF结束。唯一的异常是由于copy的工作方式,文件以0x1A终止。但是请注意,这个异常不会对“小”文件造成问题.;

通过额外的测试,我确认如下:

  • 在二进制文件中使用copy/b选项会阻止添加0x1A字符,并且findstr不会挂起3GB文件。
  • 用不同的字符终止3GB文件也会导致findstr挂起。
  • 0x1A字符不会在“小”文件上引起任何问题。(与其他终止字符类似。)
  • 0x1A之后添加CRLF可以解决这个问题。(LF本身可能就足够了。)
  • 使用type将文件管道到findstr中,不会挂起。(这可能是由于type|插入额外的行结束符的副作用。)
  • 使用重定向输入<也会导致findstr挂起。但这是意料之中的;如dbenham's post: "重定向输入必须以LF结尾"所解释的那样

/D对于多个目录的提示:将目录列表放在搜索字符串之前。这些都有效:

findstr /D:dir1;dir2 "searchString" *.*
findstr /D:"dir1;dir2" "searchString" *.*
findstr /D:"\path\dir1\;\path\dir2\" "searchString" *.*

正如预期的那样,如果你不以\开始目录,路径是相对于位置的。如果目录名中没有空格,则用"包围路径是可选的。结尾\是可选的。location的输出将包括您给它的任何路径。不管是否使用"包围目录列表,它都可以工作。

当几个命令被括在括号中,并且有重定向文件到整个块:

< input.txt (
command1
command2
. . .
) > output.txt

…然后,只要块中的命令处于活动状态,文件就保持打开状态,因此这些命令可能会移动重定向文件的文件指针。MORE和FIND命令在处理Stdin文件之前都将Stdin文件指针移动到文件的开头,因此同一个文件可能在块中被处理多次。例如,下面的代码:

more < input.txt >  output.txt
more < input.txt >> output.txt

... 产生与此相同的结果:

< input.txt (
more
more
) > output.txt

这段代码:

find    "search string" < input.txt > matchedLines.txt
find /V "search string" < input.txt > unmatchedLines.txt

... 产生与此相同的结果:

< input.txt (
find    "search string" > matchedLines.txt
find /V "search string" > unmatchedLines.txt
)

FINDSTR则不同;它执行将Stdin文件指针从当前位置移动。例如,这段代码在搜索行之后插入新行:

call :ProcessFile < input.txt
goto :EOF


:ProcessFile
rem Read the next line from Stdin and copy it
set /P line=
echo %line%
rem Test if it is the search line
if "%line%" neq "search line" goto ProcessFile
rem Insert the new line at this point
echo New line
rem And copy the rest of lines
findstr "^"
exit /B

我们可以在辅助程序的帮助下很好地利用这个特性,该辅助程序允许我们移动重定向文件的文件指针,如这个例子所示。

此行为由杰布这篇文章首次报告。


编辑2018-08-18: 报告了新的FINDSTR错误

FINDSTR命令有一个奇怪的错误,当这个命令用于显示字符的颜色,并且这样一个命令的输出被重定向到CON设备时发生。有关如何使用FINDSTR命令以颜色显示文本的详细信息,请参见这个话题

当这种形式的FINDSTR命令的输出被重定向到CON时,在以所需的颜色输出文本之后,会发生一些奇怪的事情:它之后的所有文本都输出为“不可见”字符,尽管更精确的描述是,文本输出为黑色背景上的黑色文本。如果使用COLOR命令重置整个屏幕的前景色和背景色,原始文本将会出现。然而,当文本“不可见”时,我们可以执行SET /P命令,这样所有输入的字符都不会出现在屏幕上。此行为可用于输入密码。

@echo off
setlocal


set /P "=_" < NUL > "Enter password"
findstr /A:1E /V "^$" "Enter password" NUL > CON
del "Enter password"
set /P "password="
cls
color 07
echo The password read is: "%password%"

我想报告一个关于在文件名中使用短破折号(-)或长破折号(-)时第一个答案中的要搜索的数据来源部分的错误。

更具体地说,如果您将要使用第一个选项——指定为参数的文件名,则不会找到该文件。只要使用选项2 - Stdin通过重定向或3 - 来自管道的数据流, findstr就会找到该文件。

例如,这个简单的批处理脚本:

echo off
chcp 1250 > nul
set INTEXTFILE1=filename with – dash.txt
set INTEXTFILE2=filename with — dash.txt


rem 3 way of findstr use with en dashed filename
echo.
echo Filename with en dash:
echo.
echo 1. As argument
findstr . "%INTEXTFILE1%"
echo.
echo 2. As stdin via redirection
findstr . < "%INTEXTFILE1%"
echo.
echo 3. As datastream from a pipe
type "%INTEXTFILE1%" | findstr .
echo.
echo.
rem The same set of operations with em dashed filename
echo Filename with em dash:
echo.
echo 1. As argument
findstr . "%INTEXTFILE2%"
echo.
echo 2. As stdin via redirection
findstr . < "%INTEXTFILE2%"
echo.
echo 3. As datastream from a pipe
type "%INTEXTFILE2%" | findstr .
echo.


pause

将打印:

带破折号的文件名:

    <李> < p >作为参数< br > 无法打开文件名- dash.txt

    .txt
  1. 作为stdin通过重定向
    我是带破折号的文件。

  2. 作为来自管道的数据流
    我是带破折号的文件。

带em破折号的文件名:

    <李> < p >作为参数< br > 无法打开文件名- dash.txt

    .txt
  1. 作为stdin通过重定向
    我是带有em破折号的文件。

  2. 作为来自管道的数据流
    我是带有em破折号的文件。

希望能有所帮助。

M。

findstr命令ErrorLevel(或退出代码)设置为以下值之一,前提是没有无效或不兼容的开关,并且没有搜索字符串超过适用的长度限制:

  • 当在所有指定文件的一行中至少遇到一个匹配时,0;
  • 1否则;

在以下情况下,一行被认为包含匹配项:

  • 没有/V选项,并且搜索表达式至少出现一次;
  • /V选项被给出,搜索表达式不会出现;

这意味着/V选项也会改变返回的ErrorLevel,但它只会将还原!

例如,当你有一个文件test.txt有两行,其中一行包含字符串text,而另一行不包含,findstr "text" "test.txt"findstr /V "text" "test.txt"都返回0ErrorLevel

基本上你可以说:如果findstr返回至少一行,ErrorLevel被设置为0,否则为1

注意,/M选项不会影响ErrorLevel值,它只是改变输出。

(只是为了完整起见:find命令对于/V选项和ErrorLevel的行为完全相同;/C选项不会影响ErrorLevel。)

FINDSTR有一个颜色错误,我在https://superuser.com/questions/1535810/is-there-a-better-way-to-mitigate-this-obscure-color-bug-when-piping-to-findstr/1538802?noredirect=1#comment2339443_1538802描述并解决了这个错误

总结一下这个线程,这个错误是,如果输入在括号内的代码块中被输送到FINDSTR,内联ANSI转义颜色代码将在以后执行的命令中停止工作。内联颜色代码的一个例子是:echo %magenta%Alert: Something bad happened%yellow%(其中洋红色和黄色是前面在.bat文件中定义的变量,作为相应的ANSI转义颜色代码)。

我最初的解决方案是在FINDSTR之后调用一个什么都不做的子例程。调用或返回以某种方式“重置”需要重置的东西。

后来我发现了另一个可能更有效的解决方案:将FINDSTR短语放在括号内,如下例所示: echo success | ( FINDSTR /R success ) 将FINDSTR短语放置在嵌套代码块中似乎可以隔离FINDSTR的colorcode错误,这样它就不会影响嵌套代码块之外的内容。也许这个技术还可以解决其他一些不希望看到的FINDSTR副作用