前言
本回答中的许多信息都是基于在Vista机器上运行的实验收集而来的。除非明确说明,否则我没有确认这些信息是否适用于其他Windows版本。
FINDSTR输出
文档从未费心解释FINDSTR的输出。它暗示了匹配的行将被打印出来,但没有更多的解释。
匹配行的输出格式如下:
文件名:行号:行偏移量:文本
其中
文件名: = 包含匹配行的文件的名称。如果请求是针对单个文件的,或者搜索管道输入或重定向输入,则不打印文件名。当打印时,文件名将始终包括提供的任何路径信息。如果使用了/S
选项,则会添加额外的路径信息。打印的路径始终相对于提供的路径,或者如果没有提供,则相对于当前目录。
注意 - 当搜索多个文件时,可以使用
非标准(且文档不完善)通配符<
和
>
来避免文件名前缀。这些通配符的工作规则可以在
此处找到。最后,您可以查看此
示例以了解非标准通配符如何与FINDSTR一起使用。
lineNumber: = 匹配行的行号,表示为十进制值,其中1表示输入的第1行。仅在指定了
/N
选项时打印。
lineOffset: = 匹配行的十进制字节偏移量,其中0表示第一行的第一个字符。仅在指定了
/O
选项时才打印。这不是行内匹配的偏移量。它是从文件开头到行开头的字节数。
text = 匹配行的二进制表示,包括任何<CR>和/或<LF>。二进制输出不会留下任何内容,因此匹配所有行的示例将生成原始文件的精确二进制副本。
FINDSTR "^" FILE >FILE_COPY
/A 选项仅设置 fileName:、lineNumber: 和 lineOffset: 输出的颜色。 匹配行的文本始终以当前控制台颜色输出。 /A 选项仅在直接显示到控制台时才有效果。如果输出被重定向到文件或管道,则 /A 选项无效。请参见2018-08-18 Aacini 在答案中的编辑,了解当输出被重定向到 CON 时出现故障行为的描述。
大多数控制字符和许多扩展 ASCII 字符在 XP 上显示为点
XP 上的 FINDSTR 将匹配行中的大多数不可打印控制字符显示为点(句号)在屏幕上。以下控制字符是例外:0x09 制表符、0x0A 换行符、0x0B 垂直制表符、0x0C 换页符、0x0D 回车符。
XP FINDSTR 还将许多扩展 ASCII 字符转换为点。在 XP 上显示为点的扩展 ASCII 字符与在命令行中提供时转换的字符相同。请参见本帖子后面的“命令行参数的字符限制 - 扩展 ASCII 转换”部分。
控制字符和扩展ASCII字符如果输出被管道、重定向到文件或在FOR IN()子句中,不会在XP上转换成点号。
Vista和Windows 7始终以它们自己的形式显示所有字符,而不是点号。
返回代码(ERRORLEVEL):
- 0(成功)
- 1(失败)
- 在任何文件的任何行中都没有找到匹配项。
- 由
/A:xx
选项指定的颜色无效。
- 2(错误)
- 同时指定了不兼容的选项
/L
和/R
。
/A:
、/F:
、/C:
、/D:
或/G:
后缺少参数。
- 由
/F:file
或/G:file
指定的文件未找到。
- 255(错误)
搜索数据源 (根据使用 Windows 7 的测试更新)
Findstr 可以从以下数据源中搜索数据:
作为参数指定的文件名和/或使用 /F:file
选项。
通过重定向的标准输入 findstr "searchString" <file
来自管道的数据流 type file | findstr "searchString"
参数/选项优先于重定向,重定向优先于管道数据。
文件名参数和 /F:file
可以组合使用。可以使用多个文件名参数。如果指定了多个 /F:file
选项,则仅使用最后一个选项。通配符允许在文件名参数中使用,但不允许在由 /F:file
指定的文件中使用。
搜索字符串的来源 (根据使用 Windows 7 的测试更新)
/G:file
和 /C:string
选项可以组合使用,可以指定多个 /C:string
选项。如果指定了多个 /G:file
选项,则只使用最后一个选项。如果使用了 /G:file
或 /C:string
中的任何一个选项,则所有非选项参数都被认为是要进行搜索的文件。如果既没有使用 /G:file
也没有使用 /C:string
,则第一个非选项参数被视为用空格分隔的搜索词列表。
使用 /F:FILE
选项时,文件名不能在文件内加引号。
文件名可能包含空格和其他特殊字符。大多数命令要求使用引号括起来。但是,使用 FINDSTR 的 /F:files.txt
选项时,必须在 files.txt 文件中的文件名不加引号。如果文件名加了引号,则无法找到该文件。
BUG - 短的8.3文件名可能会破坏/D和/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
这样排序较晚的其他文件也会被错过。
每个搜索的目录都是独立处理的。例如,
/S
选项在父文件夹中未找到文件后会成功开始在子文件夹中搜索,但是一旦漏洞导致在子文件夹中错过了一个短文件名,则该子文件夹中的所有后续文件也将被错过。
如果在禁用NTFS 8.3名称生成的机器上创建相同的文件名,则命令可以正常工作。当然,
b.txt2
将无法找到,但
c.txt
将被正确找到。
并非所有的短名称都会触发该漏洞。我见过的所有有问题的行为实例都涉及扩展名超过3个字符的带有短8.3名称的文件,其起始与不需要8.3名称的普通名称相同。
已确认该漏洞存在于XP、Vista和Windows 7中。
不可打印字符和/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
选项跳过文件。
管道和重定向输入可能会添加<CR><LF>
如果输入是通过管道传递的,并且流的最后一个字符不是<LF>
,那么FINDSTR将自动在输入末尾添加<CR><LF>
。这在XP、Vista和Windows 7上已经得到确认。(我曾经认为Windows管道负责修改输入,但我后来发现实际上是FINDSTR在进行修改。)
对于Vista上的重定向输入也是如此。如果用作重定向输入的文件的最后一个字符不是<LF>
,那么FINDSTR将自动在输入末尾添加<CR><LF>
。然而,XP和Windows 7不会改变重定向输入。
在XP和Windows 7上,如果重定向的输入文件不以结尾,则FINDSTR会挂起。这是一个讨厌的“特性”。一旦到达重定向文件的末尾,FINDSTR将无限期地挂起。
如果输入是通过管道传输的,并且最后一行由单个字符组成且没有跟随,则FINDSTR将完全忽略最后一行。
示例-第一个只有一个字符且没有的命令无法匹配,但第二个有2个字符的命令可以正常工作,第三个具有终止换行符的一个字符的命令也可以正常工作。
> set /p "=x" <nul | findstr "^"
> set /p "=xx" <nul | findstr "^"
xx
> echo x| findstr "^"
x
由DosTips用户Sponge Belly在new findstr bug上报告。已在XP、Windows 7和Windows 8上确认。还没有关于Vista的消息。(我不再拥有Vista进行测试)。
选项语法
选项字母不区分大小写,因此/i
和/I
是等效的。
选项可以以/
或-
为前缀
选项可以在单个/
或-
后连接。但是,连接的选项列表最多只能包含一个OFF或F:等多字符选项,并且多字符选项必须是列表中的最后一个选项。
以下是表达任何顺序包含“hello”和“goodbye”的不区分大小写正则表达式搜索的等效方式
/i /r /c:"hello.*goodbye" /c:"goodbye.*hello"
-i -r -c:"hello.*goodbye" /c:"goodbye.*hello"
/irc:"hello.*goodbye" /c:"goodbye.*hello"
选项也可以用引号括起来。因此,/i
、-i
、"/i"
和"-i"
都是等价的。同样地,/c:string
、"/c":string
、"/c:"string
和"/c:string"
都是等价的。
如果搜索字符串以斜杠/
或减号-
开头,则必须使用/C
或/G
选项。感谢Stephan在评论中报告了这个问题(已删除)。
如果使用了
/c:string
或
/g:file
选项,则即使加上引号,命令也会因文件名参数以
-
开头而失败。这是因为没有搜索字符串参数,所以文件名参数被视为选项。最简单的解决方法是在文件参数前加上点和反斜杠,例如
findstr /c:"searchString" ".\-fileName.txt"
搜索字符串长度限制
在 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 error: "Search string too long": How to extract and match substring in "for" loop?
XP 限制为 127 字节,适用于字面和正则搜索。
行长度限制
作为命令行参数或通过 /F:FILE 选项指定的文件没有已知的行长度限制。成功运行了针对一个不包含单个 <LF> 的 128MB 文件的搜索。
Piped数据和重定向输入每行限制为8191个字节。这个限制是FINDSTR的“特性”。它不是管道或重定向本身的固有特性。使用重定向stdin或管道输入的FINDSTR永远不会匹配任何大于等于8k字节的行。大于等于8k的行会生成一个错误消息到stderr,但如果搜索字符串至少在一个文件的至少一行中找到,则ERRORLEVEL仍然为0。
默认搜索类型:字面值与正则表达式
/C:“string”
- 默认值为/L字面值。明确将/L选项与/C:“string”组合肯定有效,但是多余的。
"string argument"
- 默认取决于第一个搜索字符串的内容。 (请记住,<space>用于分隔搜索字符串。)如果第一个搜索字符串是包含至少一个未转义元字符的有效正则表达式,则所有搜索字符串都被视为正则表达式。否则,所有搜索字符串都将被视为字面值。例如,"51.4 200"
将被视为两个正则表达式,因为第一个字符串包含一个未转义的点,而"200 51.4"
将被视为两个字面值,因为第一个字符串不包含任何元字符。
/G:file
- 默认取决于文件中第一行非空行的内容。如果第一个搜索字符串是包含至少一个未转义元字符的有效正则表达式,则所有搜索字符串都被视为正则表达式。否则,所有搜索字符串都将被视为字面值。
建议-始终在使用"string argument"
或/G:file
时明确指定/L
字面量选项或/R
正则表达式选项。
Bug-指定多个字面搜索字符串可能会导致不可靠的结果
以下简单的FINDSTR示例未能找到匹配项,尽管它应该可以。
echo ffffaaa|findstr /l "ffffaaa faffaffddd"
这个bug已在Windows Server 2003,Windows XP,Vista和Windows 7上确认。
根据实验,如果满足以下所有条件,FINDSTR可能会失败:
- 搜索使用多个文字搜索字符串
- 搜索字符串长度不同
- 短搜索字符串与长搜索字符串有一定重叠
- 搜索区分大小写(没有/I选项)
在我看到的每一个失败中,总是较短的搜索字符串失败。
更多信息请参见
为什么这个带有多个文字搜索字符串的FINDSTR示例找不到匹配项?。
命令行参数中的引号和反斜杠
注意:用户MC ND的评论反映了这一部分实际上非常复杂的规则。涉及到三个不同的解析阶段:
此突出显示部分的其余部分并不完全正确。它可以作为许多情况的指南,但是要完全理解,需要遵循上述规则。
在命令行搜索字符串中转义引号
命令行搜索字符串中的引号必须使用反斜杠进行转义,例如\"
。这适用于文字和正则表达式搜索字符串。这已在XP、Vista和Windows 7上得到确认。
注意:引号也可能需要在CMD.EXE解析器中进行转义,但这与FINDSTR无关。例如,要搜索单引号,可以使用:
FINDSTR \^" file && echo found || echo not found
在命令行文字搜索字符串中转义反斜杠
文字搜索字符串中的反斜杠通常可以表示为\
或\\
。它们通常是等效的。(在Vista中可能存在一些异常情况,其中必须始终转义反斜杠,但我没有Vista机器进行测试)。
但是有一些特殊情况:
当搜索连续的反斜杠时,除了最后一个之外,其余都必须转义。最后一个反斜杠可以选择转义。
\\
可以编码为\\\
或\\\\
\\\
可以编码为\\\\\
或\\\\\\
在引号之前搜索一个或多个反斜杠是奇怪的。逻辑会认为引号必须被转义,并且每个前置反斜杠都需要被转义,但是这样不起作用!相反,必须双倍转义每个前置反斜杠,并正常转义引号:
\"
必须编码为\\\\\"
\\"
必须编码为\\\\\\\\\"
如前所述,一个或多个转义引号可能还需要使用^
进行CMD解析器的转义
此部分中的信息已在XP和Windows 7上得到确认。
在命令行正则表达式搜索字符串中转义反斜杠
Vista only: 正则表达式中的反斜杠必须要么双倍转义,例如\\\\
,要么在字符类集合中单独转义,例如[\\]
在/G:FILE文字搜索字符串中转义引号和反斜杠
在由/G:file指定的文字搜索字符串文件中,独立的引号和反斜杠不需要转义,但是可以转义。
"
和\"
是等价的。
\
和\\
是等价的。
如果意图查找\\,则至少需要转义前导反斜杠。\\\
和\\\\
都可以使用。
如果意图查找",则至少需要转义前导反斜杠。\\"
和\\\"
都可以使用。
在/G:FILE正则表达式搜索字符串中转义引号和反斜杠
这是唯一一个根据文档预期工作的情况。引号不是正则表达式元字符,因此不需要转义(但可以转义)。反斜杠是正则表达式元字符,因此必须转义。
命令行参数的字符限制 - 扩展ASCII转换
在命令行上的任何字符串中不能出现空字符(0x00)。其他单字节字符可以出现在字符串中(0x01 - 0xFF)。然而,FINDSTR会将许多在命令行参数中发现的扩展ASCII字符转换为其他字符。这有两个主要影响:
如果在命令行上用作搜索字符串,则许多扩展ASCII字符将无法与自身匹配。这个限制对于字面和正则搜索都是一样的。如果搜索字符串必须包含扩展ASCII,则应该使用/G:FILE
选项。
如果名称包含扩展ASCII字符并且文件名在命令行上指定,则FINDSTR可能无法找到文件。如果要搜索的文件名包含扩展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>
)包含到环境变量中,并在命令行参数中使用延迟扩展是最简单的方法。
/G:FILE和/F:FILE选项指定的文件中找到的字符串的字符限制
nul(0x00)字符可以出现在文件中,但它的作用类似于C字符串终止符。在nul字符之后的任何字符都会被视为另一个字符串,就好像它们在另一行上一样。
<CR>
和<LF>
字符被视为终止字符串的行终止符,并且不包含在字符串中。
所有其他单字节字符都完美地包含在字符串中。
搜索Unicode文件
由于FINDSTR无法搜索nul字节,而Unicode通常包含许多nul字节,因此不能正确地搜索大多数Unicode(UTF-16、UTF-16LE、UTF-16BE、UTF-32)。
然而,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字符。
行尾
FINDSTR在每个之后立即断开行。是否有对行断开没有影响。
跨行搜索
如预期,.
正则表达式元字符将不匹配<CR>或<LF>。但是可以使用命令行搜索字符串跨行搜索。必须显式匹配<CR>和<LF>字符。如果找到多行匹配,则仅打印匹配的第一行。 FINDSTR然后返回源文件中的第二行并重新开始搜索 - 类似于“向前查看”功能。
假设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>或<LF>的唯一方法是通过正则表达式字符类范围表达式,该表达式夹在EOL字符之间。
注意:上面是正则表达式字节流的符号表示,因为我无法以图形方式表示字符。
答案在下面的第二部分中继续...
grep
。这个工具非常被理解和有文档说明 :-) 比如,可参考 https://dev59.com/JXE85IYBdhLWcg3wvGKm 。 - paxdiablo