前言
这个答案中的大部分信息都是基于在Vista机器上运行的实验而收集的。除非另有明确说明,我还没有确认这些信息是否适用于其他Windows版本。
中输出
文档从未费心解释FINDSTR的输出。它暗示了打印匹配行的事实,但仅此而已。
匹配行输出格式如下:
filename: lineNumber lineOffset:文本
在哪里
fileName: =包含匹配行的文件名。如果请求显式地针对单个文件,或者搜索管道输入或重定向输入,则不会打印文件名。打印时,fileName将始终包含所提供的任何路径信息。如果使用了/S选项,则会添加其他路径信息。打印的路径总是相对于提供的路径,如果没有提供,则相对于当前目录。
注意:在搜索多个文件时,可以通过使用非标准通配符<和>来避免文件名前缀。这些通配符如何工作的确切规则可以在这里找到。最后,您可以看看这个例子,看看非标准通配符如何与FINDSTR一起工作。
lineNumber: =匹配行的行号,表示为十进制值,1表示输入的第一行。只有指定/N选项时才打印。
lineOffset: =匹配行开始的十进制字节偏移量,0表示第一行的第一个字符。仅在指定/O选项时打印。这不是行内匹配的偏移量。它是从文件开始到行开始的字节数。
text =匹配行的二进制表示,包括任何<CR>和/或<LF>。二进制输出中没有遗漏任何内容,因此这个匹配所有行的示例将生成原始文件的精确二进制副本。
FINDSTR "^" FILE >FILE_COPY
/A选项只设置fileName:、lineNumber:和lineOffset:输出的颜色。匹配行的文本总是以当前控制台颜色输出。/A选项仅在输出直接显示到控制台时有效。如果输出被重定向到文件或管道,/A选项将不起作用。关于输出重定向到CON时的错误行为的描述,请参见Aacini回答中的2018-08-18编辑。
大多数控制字符和许多扩展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指定的文件:文件或/G指定的文件未找到
255(错误)
太多正则表达式字符类术语
请参见答案的第2部分Regex字符类的期限限制和BUG
要搜索的数据源(根据Windows 7测试更新)
Findstr只能从以下来源之一搜索数据:
指定为参数和/或使用/F:file选项的文件名。
通过重定向findstr "searchString" <文件
来自管道类型文件的数据流
参数/选项优先于重定向,重定向优先于管道数据。
文件名参数和/F: File可以组合使用。可以使用多个文件名参数。如果指定了多个/F:文件选项,则只使用最后一个。文件名参数中允许通配符,但在/F:file指向的文件中不允许。
搜索字符串的来源(根据Windows 7测试更新)
/G:file和/C:string选项可以组合使用。可以指定多个/C:string选项。如果指定了多个/G:文件选项,则只使用最后一个。如果使用/G:file或/C:string,则所有非选项参数都假定为要搜索的文件。如果既没有使用/G:file也没有使用/C:string,那么第一个非选项参数将被视为一个以空格分隔的搜索词列表。
当使用/F: File选项时,文件名不能在文件中引用。
文件名可能包含空格和其他特殊字符。大多数命令要求这样的文件名加引号。但是FINDSTR /F:files.txt选项要求files.txt中的文件名不能被引用。如果文件名被引用,则无法找到该文件。
短小的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。一旦bug被触发,稍后排序的其他文件(如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不改变重定向输入。
如果重定向输入不以<LF>结束,FINDSTR挂起在XP和Windows 7上
这是XP和Windows 7上一个令人讨厌的“功能”。如果用作重定向输入的文件的最后一个字符不以<LF>结尾,那么FINDSTR在到达重定向文件的末尾时将无限期挂起。
如果管道数据的最后一行由单个字符组成,则可以忽略它
如果输入是通过管道输入的,并且最后一行由单个字符组成,后面没有<LF>,那么FINDSTR完全忽略最后一行。
示例-第一个带有单个字符且没有<LF>的命令无法匹配,但是第二个带有2个字符的命令可以正常工作,第三个带有一个字符的结束换行符的命令也是如此。
> 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了)。
选项的语法
选项字母不区分大小写,因此/i和/i是等效的。
选项可以用“/”或“-”作为前缀
选项可以在单个/或-后连接。但是,连接的选项列表最多只能包含一个多字符选项,例如OFF或F:,并且该多字符选项必须位于列表的最后。
以下是对任意顺序同时包含“hello”和“goodbye”的行进行不区分大小写正则表达式搜索的等效方法
/i /r /c:"hello. "*再见”/ c:“再见。*你好”
-i -r -c:"你好。*再见”/ c:“再见。*你好”
/ irc:“你好。*再见”/ c:“再见。*你好”
期权也可以报价。所以/i -i /i和-i都是等价的。同样,/c:string、"/c":string、"/c:"string和"/c:string"都是等价的。
如果搜索字符串以/或-字面值开头,则必须使用/C或/G选项。感谢Stephan在评论中报告了这一点(已删除)。
如果使用了/c:string或/g:file选项,那么如果文件名参数以-开头,即使引用也会失败。这是因为没有搜索字符串参数,因此文件名参数被视为一个选项。最简单的解决方法是在file参数前加上。反斜杠,如
findstr /c:"searchString" ".\-fileName.txt"
搜索字符串长度限制
在Vista上,单个搜索字符串允许的最大长度是511字节。如果任何搜索字符串超过511,则结果是FINDSTR:搜索字符串太长。error为ERRORLEVEL 2。
使用正则表达式进行搜索时,最大搜索字符串长度为254。长度在255到511之间的正则表达式将导致一个ERRORLEVEL 2的FINDSTR: Out of memory错误。长度为>511的正则表达式会导致FINDSTR: Search字符串过长。错误。
在Windows XP上,搜索字符串的长度明显更短。Findstr错误:“搜索字符串太长”:如何提取和匹配子字符串在“for”循环?
对于文字和正则表达式搜索,XP限制都是127字节。
线长限制
作为命令行参数或通过/F:FILE选项指定的文件没有已知的行长限制。成功对不包含单个<LF>的128MB文件运行搜索。
管道数据和重定向输入每行限制为8191字节。这个限制是FINDSTR的一个“特性”。它不是管道或重定向所固有的。使用重定向stdin或管道输入的FINDSTR将永远不会匹配>=8k字节的任何行。Lines >= 8k向stderr生成错误消息,但是如果在至少一个文件的至少一行中找到了搜索字符串,ERRORLEVEL仍然为0。
默认搜索类型:文字vs正则表达式
/C:"string" -默认为/L文字。显式地组合/L选项和/C:"string"当然可以,但这是多余的。
"string argument" - The default depends on the content of the very first search string. (Remember that <space> is used to delimit search strings.) If the first search string is a valid regular expression that contains at least one un-escaped meta-character, then all search strings are treated as regular expressions. Otherwise all search strings are treated as literals. For example, "51.4 200" will be treated as two regular expressions because the first string contains an un-escaped dot, whereas "200 51.4" will be treated as two literals because the first string does not contain any meta-characters.
/G:file -默认值取决于文件中第一个非空行的内容。如果第一个搜索字符串是一个有效的正则表达式,包含至少一个未转义的元字符,那么所有搜索字符串都被视为正则表达式。否则,所有搜索字符串都被视为字面量。
建议-当使用"string argument"或/G:file时,总是显式指定/L文字选项或/R正则表达式选项。
指定多个文字搜索字符串会给出不可靠的结果
下面的简单FINDSTR示例无法找到匹配,尽管它应该找到匹配。
echo ffffaaa|findstr /l "ffffaaa faffaffddd"
此错误已在Windows Server 2003、Windows XP、Vista和Windows 7上确认。
根据实验,如果满足以下所有条件,FINDSTR可能会失败:
搜索使用多个文字搜索字符串
搜索字符串的长度不同
短搜索字符串与长搜索字符串有一定的重叠
搜索区分大小写(no /I选项)
在我所见过的每一次失败中,失败的总是一个较短的搜索字符串。
有关更多信息,请参阅为什么这个FINDSTR示例与多个文字搜索字符串无法找到匹配?
Quotes and backslahses within command line arguments
Note - User MC ND's comments reflect the actual horrifically complicated rules for this section. There are 3 distinct parsing phases involved:
First cmd.exe may require some quotes to be escaped as ^" (really nothing to do with FINDSTR)
Next FINDSTR uses the pre 2008 MS C/C++ argument parser, which has special rules for " and \
After the argument parser finishes, FINDSTR additionally treats \ followed by an alpha-numeric character as literal, but \ followed by non-alpha-numeric character as an escape character
The remainder of this highlighted section is not 100% correct. It can serve as a guide for many situations, but the above rules are required for total understanding.
Escaping Quote within command line search strings Quotes within command line search strings must be escaped with backslash like
\". This is true for both literal and regex search strings. This
information has been confirmed on XP, Vista, and Windows 7.
Note: The quote may also need to be escaped for the CMD.EXE parser, but this has nothing to do with FINDSTR. For example, to search for a
single quote you could use:
FINDSTR \^" file && echo found || echo not found
Escaping Backslash within command line literal search strings Backslash in a literal search string can normally be represented as
\ or as \\. They are typically equivalent. (There may be unusual
cases in Vista where the backslash must always be escaped, but I no
longer have a Vista machine to test).
But there are some special cases:
When searching for consecutive backslashes, all but the last must be
escaped. The last backslash may optionally be escaped.
\\ can be coded as \\\ or \\\\
\\\ can be coded as \\\\\ or \\\\\\
Searching for one or more backslashes before a quote is bizarre. Logic
would suggest that the quote must be escaped, and each of the leading
backslashes would need to be escaped, but this does not work! Instead,
each of the leading backslashes must be double escaped, and the quote
is escaped normally:
\" must be coded as \\\\\"
\\" must be coded as \\\\\\\\\"
As previously noted, one or more escaped quotes may also require escaping with ^ for the CMD parser
The info in this section has been confirmed on XP and Windows 7.
Escaping Backslash within command line regex search strings
Vista only: Backslash in a regex must be either double escaped like \\\\, or else single escaped within a character class set like
[\\]
XP and Windows 7: Backslash in a regex can always be represented as [\\]. It can normally be represented as \\. But this never
works if the backslash precedes an escaped quote.
One or more backslashes before an escaped quote must either be
double escaped, or else coded as [\\]
\" may be coded as \\\\\" or [\\]\"
\\" may be coded as \\\\\\\\\" or [\\][\\]\" or \\[\\]\"
转义/G:FILE文本搜索字符串中的引号和反斜杠
由/G:file指定的文字搜索字符串文件中的独立引号和反斜杠不需要转义,但可以进行转义。
“和”是等价的。
\和\\是等价的。
如果目的是查找\\,那么至少必须转义前导反斜杠。\\\和\\\\都可以。
如果目的是查找",那么至少前导反斜杠必须转义。“\\”和“\\\”都能用。
转义/G:FILE正则表达式搜索字符串中的引号和反斜杠
这是转义序列按照文档的预期工作的一种情况。Quote不是正则表达式元字符,因此不需要转义(但可以转义)。反斜杠是正则表达式元字符,因此必须转义。
命令行参数的字符限制。扩展ASCII转换
空字符(0x00)不能出现在命令行的任何字符串中。任何其他单字节字符都可以出现在字符串(0x01 - 0xFF)中。但是,FINDSTR将在命令行参数中找到的许多扩展ASCII字符转换为其他字符。这在两个方面产生了重大影响:
Many extended ASCII characters will not match themselves if used as a search string on the command line. This limitation is the same for literal and regex searches. If a search string must contain extended ASCII, then the /G:FILE option should be used instead.
FINDSTR may fail to find a file if the name contains extended ASCII characters and the file name is specified on the command line. If a file to be searched contains extended ASCII in the name, then the /F:FILE option should be used instead.
下面是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字符串结束符。null字符之后的任何字符都被视为不同的字符串,就像它们在另一行一样。
<CR>和<LF>字符被视为终止字符串的行终止符,不包含在字符串中。
所有其他单字节字符都被完美地包含在字符串中。
搜索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字符。
行结束
FINDSTR在每个<LF>后立即换行。<CR>是否存在对换行符没有影响。
跨换行符搜索
不出所料,。regex元字符将不匹配<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字符。
[<TAB>-<0x0B>]匹配<LF>,但它也匹配<TAB>和<0x0B>
(< 0 x0c > - - - - - - !]匹配<CR>,但它也匹配<0x0C>和!
注意——以上是正则字节流的符号表示,因为我不能图形化地表示这些字符。
在第二部分继续回答…