Windows FINDSTR 命令都有哪些未记录的功能和限制?
Posted
技术标签:
【中文标题】Windows FINDSTR 命令都有哪些未记录的功能和限制?【英文标题】:What are the undocumented features and limitations of the Windows FINDSTR command?Windows FINDSTR 命令有哪些未记录的功能和限制? 【发布时间】:2012-02-09 07:40:35 【问题描述】:Windows FINDSTR 命令的文档非常糟糕。可以通过FINDSTR /?
或HELP FINDSTR
获得非常基本的命令行帮助,但它还远远不够。 https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/findstr 有更多在线文档。
有许多 FINDSTR 功能和限制在文档中甚至都没有提示。如果没有先验知识和/或仔细的实验,也无法预料到它们。
所以问题是 - 未记录的 FINDSTR 功能和限制是什么?
这个问题的目的是提供一个包含许多未记录功能的一站式存储库,以便:
A) 开发人员可以充分利用现有的功能。
B) 开发人员不会浪费时间去思考为什么某些东西在看起来应该起作用的时候却不起作用。
在回复之前,请确保您了解现有文档。如果该信息包含在 HELP 中,则不属于此处。
这里也不是展示 FINDSTR 有趣用途的地方。如果一个有逻辑的人可以根据文档预测 FINDSTR 的特定用法的行为,那么它不属于这里。
同样,如果一个有逻辑的人可以根据任何现有答案中包含的信息预测特定用法的行为,那么同样,它不属于这里。
【问题讨论】:
或者,或者,您可以完全放弃糟糕的无证 MS 实用程序并安装/使用grep
, 非常了解和记录 :-) 请参阅 ***.com/questions/2635740/… 了解例子。
无论如何,如果您可以使用 FINDSTR 以外的其他东西,那么强烈建议您这样做。但是有些人处于禁止使用 3rd 方实用程序的环境中。
没有冒犯。我认真考虑过加入我自己的与您的评论类似的 FINDSTR 免责声明! :)
我对有人会发现这个问题“不具建设性”并投票结束感到震惊和失望。为了避免“意见、辩论、争论、投票或扩展讨论”,对这个问题进行了很多思考。该问题已经发布了 3.5 个月,并且没有出现任何引用的负面信息。成对的答案充满了事实,需要许多小时的艰苦研究和实验。
部分读者可能对 findstr 命令的历史背景感兴趣:blogs.msdn.com/b/oldnewthing/archive/2012/11/28/10372436.aspx
【参考方案1】:
前言此答案中的大部分信息都是根据在 Vista 机器上运行的实验收集的。除非另有明确说明,否则我尚未确认该信息是否适用于其他 Windows 版本。
FINDSTR 输出 该文档从不费心解释 FINDSTR 的输出。它暗示了打印匹配行的事实,但仅此而已。
匹配行输出格式如下:
文件名:lineNumber:lineOffset:text
在哪里
fileName: = 包含匹配行的文件的名称。如果请求明确地针对单个文件,或者搜索管道输入或重定向输入,则不会打印文件名。打印时,文件名将始终包含提供的任何路径信息。如果使用/S
选项,将添加额外的路径信息。打印的路径总是相对于提供的路径,如果没有提供,则相对于当前目录。
注意 - 使用 non-standard (and poorly documented) wildcards <
和 >
搜索多个文件时,可以避免文件名前缀。这些通配符如何工作的确切规则可以在here 中找到。最后大家可以看看这个example of how the non-standard wildcards work with FINDSTR。
lineNumber: = 匹配行的行号,以十进制值表示,1 表示输入的第一行。仅在指定 /N
选项时打印。
lineOffset: = 匹配行开头的十进制字节偏移量,0 代表第一行的第一个字符。仅在指定 /O
选项时打印。这是不是行内匹配的偏移量。它是从文件开头到行首的字节数。
text = 匹配行的二进制表示,包括任何
FINDSTR "^" FILE >FILE_COPY
/A 选项设置 fileName:、lineNumber: 和 lineOffset: 的颜色仅输出。匹配行的文本始终以当前控制台颜色输出。 /A 选项仅在输出直接显示到控制台时才有效。如果输出被重定向到文件或管道,则 /A 选项无效。有关将输出重定向到 CON 时的错误行为的描述,请参阅 2018-08-18 edit in Aacini's answer。
大多数控制字符和许多扩展 ASCII 字符在 XP 上显示为点 XP 上的 FINDSTR 将匹配行中的大多数不可打印控制字符显示为屏幕上的点(句点)。以下控制字符是例外;它们显示为自己:0x09 Tab、0x0A LineFeed、0x0B Vertical Tab、0x0C Form Feed、0x0D Carriage Return。
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(错误)
正则表达式字符类术语太多see Regex character class term limit and BUG in part 2 of answer
要搜索的数据源 (根据 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 不会改变重定向输入。
如果重定向输入不以 <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 在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 在评论中报告此问题(已删除)。
搜索字符串长度限制
在 Vista 上,单个搜索字符串的最大允许长度为 511 个字节。如果任何搜索字符串超过 511,则结果是 FINDSTR: Search string too long.
错误,ERRORLEVEL 2。
进行正则表达式搜索时,最大搜索字符串长度为 254。长度在 255 和 511 之间的正则表达式将导致 FINDSTR: Out of memory
错误,ERRORLEVEL 2。正则表达式长度 >511 将导致 @987654420 @错误。
在 Windows XP 上,搜索字符串的长度显然更短。 Findstr error: "Search string too long": How to extract and match substring in "for" loop? 文字和正则表达式搜索的 XP 限制为 127 个字节。
行长限制
指定为命令行参数或通过 /F:FILE 选项指定的文件没有已知的行长度限制。已成功针对不包含单个
管道数据和重定向输入限制为每行 8191 个字节。此限制是 FINDSTR 的“功能”。它不是管道或重定向所固有的。使用重定向标准输入或管道输入的 FINDSTR 永远不会匹配 >=8k 字节的任何行。 Lines >= 8k 会向 stderr 生成错误消息,但如果在至少一个文件的至少一行中找到搜索字符串,则 ERRORLEVEL 仍为 0。
默认搜索类型:文字与正则表达式/C:"string"
- 默认为 /L 文字。将 /L 选项与 /C:"string" 显式组合当然可以,但也是多余的。
"string argument"
- 默认值取决于第一个搜索字符串的内容。 (请记住,"51.4 200"
将被视为两个正则表达式,因为第一个字符串包含未转义的点,而 "200 51.4"
将被视为两个文字,因为第一个字符串不包含任何元字符。
/G:file
- 默认值取决于文件中第一个非空行的内容。如果第一个搜索字符串是包含至少一个未转义元字符的有效正则表达式,则所有搜索字符串都被视为正则表达式。否则所有搜索字符串都被视为文字。
建议 - 在使用 "string argument"
或 /G:file
时,始终明确指定 /L
文字选项或 /R
正则表达式选项。
BUG - 指定多个文字搜索字符串会产生不可靠的结果
以下简单的 FINDSTR 示例无法找到匹配项,即使它应该找到。
echo ffffaaa|findstr /l "ffffaaa faffaffddd"
此错误已在 Windows Server 2003、Windows XP、Vista 和 Windows 7 上得到确认。
根据实验,如果满足以下所有条件,FINDSTR 可能会失败:
搜索正在使用多个文字搜索字符串 搜索字符串的长度不同 短搜索字符串与较长搜索字符串有一定程度的重叠 搜索区分大小写(无/I
选项)
在我看到的每一次失败中,失败的总是较短的搜索字符串之一。
欲了解更多信息,请参阅Why doesn't this FINDSTR example with multiple literal search strings find a match?
命令行参数中的引号和反斜杠注意 - 用户 MC ND 的 cmets反映本节的实际极其复杂的规则。涉及 3 个不同的解析阶段:
第一个 cmd.exe 可能需要将一些引号转义为 ^"(实际上与 FINDSTR 无关) 下一个 FINDSTR 使用 pre 2008 MS C/C++ argument parser,它对 " 和 \ 有特殊规则 参数解析器完成后,FINDSTR 还将后跟字母数字字符的 \ 视为文字,但将后跟非字母数字字符的 \ 视为转义字符此突出显示部分的其余部分并非 100% 正确。它可以作为许多情况的指南,但上述规则是全面理解所必需的。
命令行搜索字符串中的转义引号命令行搜索字符串中的引号必须用反斜杠转义,例如
\"
。对于文字和正则表达式搜索字符串都是如此。这 信息已在 XP、Vista 和 Windows 7 上得到确认。注意:CMD.EXE 解析器可能还需要对引号进行转义,但这与 FINDSTR 无关。例如,要搜索一个 您可以使用单引号:
FINDSTR \^" file && echo found || echo not found
在命令行文字搜索字符串中转义反斜杠文字搜索字符串中的反斜杠通常可以表示为
\
或\\
。它们通常是等价的。 (可能有不寻常的 Vista中必须始终转义反斜杠的情况,但我没有 再有一台 Vista 机器来测试)。但也有一些特殊情况:
当搜索连续的反斜杠时,除了最后一个必须 逃脱了。最后一个反斜杠可以选择转义。
\\
可以编码为\\\
或\\\\
\\\
可以编码为\\\\\
或\\\\\\
在引用之前搜索一个或多个反斜杠是很奇怪的。逻辑 会建议必须转义引号,并且每个前导 需要转义反斜杠,但这不起作用!反而, 每个前导反斜杠都必须进行双重转义,并且引号 正常转义:
\"
必须编码为\\\\\"
\\"
必须编码为\\\\\\\\\"
如前所述,一个或多个转义引号可能还需要使用
^
转义以用于 CMD 解析器此部分中的信息已在 XP 和 Windows 7 上得到确认。
在命令行正则表达式搜索字符串中转义反斜杠
仅限 Vista: 正则表达式中的反斜杠必须像
\\\\
一样进行双重转义,或者在字符类集中进行单次转义,例如[\\]
XP 和 Windows 7: 正则表达式中的反斜杠始终可以表示为
[\\]
。它通常可以表示为\\
。但这从来 如果反斜杠在转义引号之前,则有效。转义引号前的一个或多个反斜杠必须是 双重转义,或者编码为
[\\]
\"
可以编码为\\\\\"
或[\\]\"
\\"
可以编码为\\\\\\\\\"
或[\\][\\]\"
或\\[\\]\"
在 /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 无法正确搜索大多数 Unicode(UTF-16、UTF-16LE、UTF-16BE、UTF-32),因为它无法搜索 nul 字节,而 Unicode 通常包含许多 nul 字节。
但是,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 在每个
跨行搜索
正如预期的那样,.
正则表达式元字符将不匹配
假设 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 选项搜索换行符并不精确,因为匹配
[<TAB>-<0x0B>]
匹配
[<0x0C>-!]
匹配
注意 - 以上是正则表达式字节流的符号表示,因为我无法以图形方式表示字符。
Answer continued in part 2 below...
【讨论】:
出色的完整性。要是网上所有的答案都是这样就好了。 EDIT - 将控制字符描述为 XP 上的点。还记录了源自 8.3 短文件名的错误/S
和 /D
选项。
仅供参考(我不知道您是否已经知道,但我在您的回答中没有提及)。大多数 "bizarre" 反斜杠+引号规则的原因是 findstr
是一个 exe
文件,some rules 控制参数标记器如何处理反斜杠+引号,但是一次参数被解析,findstr
代码有一个 string 需要被编译成一个 regular expression 实例。因此,有些反斜杠会被解释两次。
文字反斜杠不需要任何转义 (findstr /l \ *.cmd
),但双引号文字反斜杠需要它 (findstr /l "\\" *.cmd
) 以避免转义引号。但是findstr
字符串解析器将处理文字反斜杠,后跟一个 非字母数字字符 ([a-zA-Z0-9]
) 作为转义字符:findstr /l /c:"\ o" *.cmd
搜索一个空格,后跟一个 o
字符作为反斜杠转义空格,但findstr /l /c:"\w" *.cmd
搜索反斜杠后跟w
字符(它是字母数字,因此不会转义)
@dbenham,想知道是否应该简要介绍一下/A:
选项? FINDSTR
帮助未指定在搜索多个文件时仅对文件名进行颜色编码。可以从第一次阅读帮助中推断出它可以更改输出中找到的字符串的颜色。我想这在技术上不是一个未记录的功能或限制,但微软没有特别指出这一点似乎很奇怪。 SS64 上的文档可以。【参考方案2】:
Answer continued from part 1 above - 我已经达到了 30,000 个字符的回答限制:-(
有限的正则表达式 (regex) 支持 FINDSTR 对正则表达式的支持非常有限。如果 HELP 文档中没有,则不支持。
除此之外,支持的正则表达式以完全非标准的方式实现,因此结果可能与来自 grep 或 perl 之类的预期结果不同。
正则表达式行位置锚 ^ 和 $^
匹配输入流的开头以及紧随
$
匹配紧接在 <CR> 之前的任何位置。这意味着包含$
的正则表达式搜索字符串将永远不会匹配Unix 样式文本文件中的任何行,如果它缺少
注意 - 如前所述,通过管道传输和重定向到 FINDSTR 的输入可能会附加 <CR><LF>
,但它不在源代码中。显然这会影响使用$
的正则表达式搜索。
在^
之前或$
之后包含字符的任何搜索字符串将始终找不到匹配项。
仓位选项 /B /E /X
位置选项的作用与^
和$
相同,但它们也适用于文字搜索字符串。
/B 功能与正则表达式搜索字符串开头的^
相同。
/E 功能与正则表达式搜索字符串末尾的$
相同。
/X 的功能与在正则表达式搜索字符串的开头同时包含 ^
和在结尾的 $
相同。
正则表达式单词边界\<
必须是正则表达式中的第一个词。如果正则表达式前面有任何其他字符,则该正则表达式将不匹配任何内容。 \<
对应于输入的开头、行的开头(紧跟
\>
必须是正则表达式中的最后一个术语。如果后面有任何其他字符,正则表达式将不匹配任何内容。 \>
对应于输入的结尾、
这里是“非单词”字符的完整列表,以十进制字节码表示。 注意 - 此列表是在美国机器上编译的。我不知道其他语言可能会对这个列表产生什么影响。
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
正则表达式字符类范围 [x-y] 字符类范围不能按预期工作。请参阅此问题:Why does findstr not handle case properly (in some circumstances)?,以及此答案:https://***.com/a/8767815/1012053。
问题是 FINDSTR 没有按照字符的字节码值来整理字符(通常被认为是 ASCII 码,但 ASCII 只定义在 0x00 - 0x7F)。大多数正则表达式实现会将 [A-Z] 视为所有大写英文大写字母。但是 FINDSTR 使用的排序规则大致对应于 SORT 的工作方式。所以 [A-Z] 包括完整的英文字母表,包括大写和小写(“a”除外),以及带有变音符号的非英文字母字符。
下面是 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
正则表达式字符类术语限制和BUG FINDSTR 不仅限制在正则表达式中最多 15 个字符类术语,而且无法正确处理超出限制的尝试。使用 16 个或更多字符类术语会导致交互式窗口弹出 “查找字符串 (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 here 报告了此错误。它已在 XP、Vista 和 Windows 7 上得到确认。
如果包含字节码 0xFF(十进制 255)正则表达式搜索将失败(并且可能无限期挂起)
任何包含字节码 0xFF(十进制 255)的正则表达式搜索都将失败。如果直接包含字节码 0xFF,或者如果它隐式包含在字符类范围内,则会失败。请记住,FINDSTR 字符类范围不会根据字节码值整理字符。字符<0xFF>
出现在<space>
和<tab>
字符之间的排序序列中相对较早。因此,任何同时包含 <space>
和 <tab>
的字符类范围都将失败。
具体行为会根据 Windows 版本略有不同。如果包含 0xFF,Windows 7 将无限期挂起。 XP 不会挂起,但总是找不到匹配项,并且偶尔会打印以下错误消息 - “进程尝试写入不存在的管道。”
我无法再使用 Vista 机器,因此无法在 Vista 上进行测试。
正则表达式错误:.
和 [^anySet]
可以匹配 End-Of-File
正则表达式.
元字符应该只匹配除<CR>
或<LF>
之外的任何字符。如果文件中的最后一行未被<CR>
或<LF>
终止,则存在一个允许它匹配文件结尾的错误。但是,.
不会匹配空文件。
例如,名为“test.txt”的文件包含单行 x
,但没有终止 <CR>
或 <LF>
,将匹配以下内容:
findstr /r x......... test.txt
此错误已在 XP 和 Win7 上得到确认。
对于负字符集似乎也是如此。 [^abc]
之类的内容将匹配 End-Of-File。像[abc]
这样的正字符集似乎可以正常工作。我只在Win7上测试过。
【讨论】:
findstr 在处理大文件时也有问题。文件 > 2GB 可能会导致 findstr 挂起。它并不总是发生。在确认错误时,我搜索了一个没有挂起的 2.3GB 文件。即使只搜索一个文件,它也会挂起。解决方法是将type
的输出通过管道传输到findstr
。
可能还值得一提的是findstr
支持多个/c:
搜索字符串。我知道你的回答确实证明了这一点。但这是没有记录的东西;在使用 findstr
几年后得知该功能,我感到非常惊讶。
@CraigYoung - 关于搜索字符串来源,您是对的。我编辑了我的答案,谢谢。
经过进一步调查,它看起来像是您记录的 LF
问题的变体。我意识到我的测试文件没有以LF
结尾,因为我在附加模式下使用copy
来创建它。我已经放置了一个命令行会话来演示这个问题的答案 (***.com/a/22943056/224704)。请注意,输入未重定向,但搜索挂起。对于同样不以LF
结尾的较小文件,完全相同的搜索命令不会挂起。
新发现 (Win7): findstr /R /C:"^[0-9][0-9]* [0-3][0-9][0-9]-[0-9][0-9]:[0-5][0-9]:[0-5][0-9]\.[0-9][0-9]* [0-9]*\.[0-9]*"
(15 个字符类) -- ErrorLevel = -1073740791 (0xC0000409)
, 错误对话框窗口: Find String (QGREP) Utility has stopped working
;删除一个类或两个元字符(*\.
)后,它可以工作了......【参考方案3】:
当括号中包含多个命令并且有重定向文件到整个块时:
< input.txt (
command1
command2
. . .
) > output.txt
...那么只要块中的命令处于活动状态,文件就会保持打开状态,因此这些命令可能会移动重定向文件的文件指针。 MORE 和 FIND 命令在处理文件之前都将 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 不同;它确实不将标准输入文件指针从其当前位置移动。例如,此代码在搜索行之后插入新行:
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
我们可以通过一个辅助程序来很好地利用这个特性,它允许我们移动重定向文件的文件指针,如this example所示。
jebthis post 首次报告了此行为。
编辑 2018-08-18:报告了新的 FINDSTR 错误
FINDSTR 命令有一个奇怪的错误,当此命令用于显示彩色字符并且此类命令的输出被重定向到 CON 设备时会发生这种错误。有关如何使用 FINDSTR 命令以彩色显示文本的详细信息,请参阅this topic。
当这种形式的 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%"
【讨论】:
【参考方案4】:findstr
在搜索大文件时有时会意外挂起。
我尚未确认确切的条件或边界大小。我怀疑任何大于 2GB 的文件都可能存在风险。
我对此有过不同的经历,所以它不仅仅是文件大小。这看起来可能是 FINDSTR hangs on XP and Windows 7 if redirected input does not end with LF 的变体,但正如所证明的,当输入未重定向时,此特定问题就会出现。
以下命令行会话 (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
终止。唯一的异常是由于the way copy
works,文件以0x1A
终止。但请注意,此异常不会导致“小”文件出现问题。
通过额外的测试,我确认了以下几点:
将copy
与/b
选项一起用于二进制文件可防止添加0x1A
字符,并且findstr
不会在3GB 文件上挂起。
用不同的字符终止 3GB 文件也会导致 findstr
挂起。
0x1A
字符不会对“小”文件造成任何问题。 (对于其他终止字符也是如此。)
在0x1A
之后添加CRLF
可以解决问题。 (LF
本身可能就足够了。)
使用type
将文件通过管道传输到findstr
不会挂起。 (这可能是由于 type
或 |
的副作用会插入额外的行尾。)
使用重定向输入<
也会导致findstr
挂起。 但这是意料之中的;如dbenham's post 中所述:“重定向的输入必须以LF
结尾”。
【讨论】:
+1,我可以在我的 Win7 机器上确认问题。当最后一个字符不是<LF>
时,会挂起一个大小正好为 2GiB 的文件。小两个字节的文件没有挂起。非常讨厌!【参考方案5】:
当使用 en dash (–) 或 em dash (-) 在文件名中。
更具体地说,如果您要使用第一个选项 - 指定为参数的文件名,将找不到该文件。只要您使用选项 2 - stdin via redirection 或 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
将打印:
带破折号的文件名:
作为参数FINDSTR:无法使用 - dash.txt 打开文件名
通过重定向作为标准输入我是带有短划线的文件。
作为来自管道的数据流我是带有短划线的文件。
带有破折号的文件名:
作为参数FINDSTR:无法使用 - dash.txt 打开文件名
通过重定向作为标准输入我是带有 em 破折号的文件。
作为来自管道的数据流我是带有 em 破折号的文件。
希望对你有帮助。
M.
【讨论】:
嗨,matro,虽然您的 cmets 可能是正确的,但我不确定他们没有解决实际问题。 我相信这是一个 unicode 问题,FINDSTR 不支持。 CMD.EXE 重定向可以正确打开带有 unicode 的文件名,TYPE 命令也可以。但是在某个地方,FINDSTR 将破折号和破折号都转换为普通破折号,当然操作系统找不到该名称。如果您创建另一个文件用短划线代替短划线和/或短划线,则 FINDSTR 将搜索短划线文件(如果提供的名称包含短划线或短划线)。 我将此问题归类为限制而不是错误。 实际上,这与其说是 unicode 问题,不如说是扩展的 ASCII。我已经在我的原始答案中记录了这个问题,标题是命令行参数的字符限制 - 扩展的 ASCII 转换。 FINDSTR 将许多扩展的 ASCII 代码转换为“相关的”真正的 ASCII,包括 en-dash 和 em-dash。【参考方案6】:findstr
command 将ErrorLevel
(or exit code) 设置为以下值之一,前提是没有无效或不兼容的开关,并且没有搜索字符串超过适用的长度限制:
0
在所有指定文件的一行中至少遇到一个匹配项时;
1
否则;
在以下情况下认为一行包含匹配项:
没有给出/V
选项,并且搜索表达式至少出现一次;
/V
选项给出,搜索表达式不出现;
这意味着/V
选项也会更改返回的ErrorLevel
,但它确实不只是恢复它!
例如,当您有一个包含两行的文件 test.txt
,其中一行包含字符串 text
但另一行不包含时,findstr "text" "test.txt"
和 findstr /V "text" "test.txt"
都返回 ErrorLevel
的 @ 987654337@.
基本上你可以说:如果findstr
至少返回一行,则ErrorLevel
设置为0
,否则设置为1
。
请注意,/M
选项不会影响ErrorLevel
的值,它只会改变输出。
(为了完整起见:find
command 与 /V
选项和 ErrorLevel
的行为方式完全相同;/C
选项不会影响 ErrorLevel
。)
【讨论】:
【参考方案7】: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 的颜色代码错误,因此它不会影响嵌套块之外的内容。也许这种技术也可以解决其他一些不希望出现的 FINDSTR 副作用。
【讨论】:
很棒的发现。但是您的规则可以简化(至少在我的企业 Windows 10 机器上)。 FINDSTR 阻止所有控制台转义序列对同一命令块中的后续命令起作用。 FINDSTR 读取管道、重定向输入还是文件都没有关系。转义序列失败不仅限于颜色代码。命令块是括号内的任何命令集,和/或通过 &、&& 或 || 连接的命令 @dbenham:很好地概括了这个问题。您知道我的解决方案(将 FINDSTR 短语嵌套在括号内)是否也适用于一般情况?你知道我的解决方案是否有任何不良副作用吗? 我没有做任何详尽的测试,但是是的,嵌套括号似乎是一个通用的解决方案,我想不出任何可能的不良副作用。【参考方案8】:/D 多个目录的提示:将目录列表放在搜索字符串之前。这些都有效:
findstr /D:dir1;dir2 "searchString" *.*
findstr /D:"dir1;dir2" "searchString" *.*
findstr /D:"\path\dir1\;\path\dir2\" "searchString" *.*
正如预期的那样,如果您不以\
开头目录,则路径是相对于位置的。如果目录名称中没有空格,则使用 "
包围路径是可选的。结尾 \
是可选的。 location 的输出将包括您提供的任何路径。无论是否使用"
包围目录列表,它都可以使用。
【讨论】:
我在这里没有看到任何未记录的内容。 /D 选项在内置帮助中进行了描述。这不是关于如何使用 FINDSTR 的一般提示的问题。它严格旨在列出未记录的功能、限制和/或错误。 @dbenham 是的,这并不是真正的无证,但我发现我必须使用 findstr 来获得我想要的结果,并分享我发现 DID 工作的内容,这样人们就不会浪费时间尝试使用以下命令不工作。 hth(我很遗憾你不喜欢我的意见 - 它只是为了建设性的) 恕我直言,/D 开关在内置帮助中明确描述:/D:dirlist Search a semicolon-delimited list of directories
并且它被放置在搜索字符串之前,所以我不明白“你找到”到底是什么/D 开关(以及什么是“不起作用的命令”)...
@Aacini 在许多语言中,属性的顺序无关紧要。我首先了解 findstr
列表 /D 的文档。是的,我对记录的功能没有任何争议,只是没有记录属性顺序很重要的问题。我只做很少的命令行工作,所以当我在拼凑一个命令时,不知道顺序有什么不同,我只是在添加属性时添加它们(按字母顺序,C 在 D 之前)。我变得非常沮丧,并与其他不经常使用命令行的人分享了我的“发现”经验。
optional 属性的顺序通常无关紧要。 findstr
文档指定 strings
部分是 NOT 可选的,您必须将它放在 optional 属性之后和 optional 文件名之前列表。如果“您发现”是使用不遵循其使用格式的命令导致错误,那么这一点是有据可查的。请参阅Command syntax:“语法按您必须键入命令及其后的任何参数的顺序显示”以上是关于Windows FINDSTR 命令都有哪些未记录的功能和限制?的主要内容,如果未能解决你的问题,请参考以下文章