BATCH 中 FINDSTR /E 匹配行尾字符串的正确语法是什么?

What is the proper syntax for FINDSTR /E in BATCH to match strings that are at the end of a line?

我正在 Batch 中编写一个子例程,它将提取字符串中间的文本,并且可以接受两组字符(如单词或短语),而不是单独的定界符作为其参数。另外,我想得到查找值的第一个字符的索引位置。我要执行此操作的方法是遍历字符并从两侧一个一个地消除它,直到查找字符串集与幸存字符串的开头和结尾匹配。

字符消除是使用变量 offset/index 完成的,例如:!_str:~%_idx%!,其中 _str 是要搜索的字符串,_idx 是偏移量计数,然后将其通过管道传输到 FINDSTR /B 以查看查找字符串是否与循环中幸存字符串的开头字符匹配。到目前为止,没问题。但是当我对正在搜索的字符串的右侧执行第二个查找字符串的过程,并将其通过管道传输到 FINDSTR /E 以查看第二个查找字符串是否与循环中幸存字符串的末尾匹配时,它不会' 似乎工作。

根据我对这些来源的理解,

FINDSTR 开关 /B/E 分别匹配行首和行尾的查找字符串。

所以,出于绝望,我创建了一些具有不同变体的测试,尽管我知道这些变体不是问题所在,但无论如何我还是做了。到目前为止,这是我尝试过的方法:

title FINDSTR_TEST
echo off
cls

setlocal EnableDelayedExpansion

set "_str=Hello World"

echo String to search: %_str%
echo:
echo Matches pattern if at the BEGINNING of a line.
echo 1: & echo %_str% | findstr /b "Hello"
echo 2: & echo %_str% | findstr /b /l "Hello"
echo 3: & echo %_str% | findstr /b /C:"Hello"
echo:
echo:
echo Matches pattern if at the END of a line.
echo 1: & echo %_str% | findstr /e "World"
echo 2: & echo %_str% | findstr /e /l "World"
echo 3: & echo %_str% | findstr /e /C:"World"
echo:
echo ERRORLEVEL: %errorlevel%

pause
endlocal
exit

实际结果如下:

String to search: Hello World

Matches pattern if at the BEGINNING of a line.
1:
Hello World
2:
Hello World
3:
Hello World


Matches pattern if at the END of a line.
1:
2:
3:

ERRORLEVEL: 1
Press any key to continue . . .

但这正是我所期待的:

String to search: Hello World

Matches pattern if at the BEGINNING of a line.
1:
Hello World
2:
Hello World
3:
Hello World


Matches pattern if at the END of a line.
1:
Hello World
2:
Hello World
3:
Hello World

ERRORLEVEL: 1
Press any key to continue . . .

这里有两个简单的问题:

  1. 我的代码是否有任何问题,尤其是在使用 /E 开关的地方?
  2. 这些 /L/C:string 开关不是多余的吗?在我看来,他们做同样的事情。

如能对这些问题作出任何澄清,我们将不胜感激。

非常感谢大家

作为我评论的后续,如果您创建一个三行批处理文件,您应该能够准确地看到发生了什么,就像这样:

Echo Hello World | FindStr /B "Hello"
(Echo Hello World) | FindStr /E "World"
@Pause

输出将显示空白,您没有特别添加它的地方:


C:\Users\SpaghettiCode>Echo Hello World   | FindStr /B "Hello"
Hello World

C:\Users\SpaghettiCode>(Echo Hello World )  | FindStr /E "World"
Press any key to continue . . .

我的首选解决方案是使用 Set /P 而不是 Echo,因为可以使用双引号和重定向专门终止输出。例如:

@Echo Off
SetLocal EnableExtensions
Title FINDSTR_TEST
ClS
Set "_str=Hello World"
Echo String to search: %_str%
Echo(
Echo Matches pattern if at the BEGINNING of a line.
Echo 1:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /B /I /R "Hello"
Echo 2:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /B /I /L "Hello"
Echo 3:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /B /I /R /C:"Hello"
Echo 4:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "^Hello"
Echo 5:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "^Hello\>"
Echo(
Echo(
Echo Matches pattern if at the END of a line.
Echo 1:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /E /I /R "World"
Echo 2:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /E /I /L "World"
Echo 3:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /E /I /R /C:"World"
Echo 4:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "World$"
Echo 5:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "\<World$"
Echo(
Echo ERRORLEVEL: %ErrorLevel%
Pause
Exit /B

如您所见,我为每个示例添加了几个额外的选项,对我来说,这些选项可能对您提供的示例字符串更有用。您还会注意到,我在测试编号之后移动了您的符号,以显示您正在打印 number colon space,而不是 number colon .

正如其他人已经指出的那样,管道前面的 SPACE 也被输出,因此包含在 findstr 处理的字符串中。

但是,一般来说,要通过管道安全地传递字符串,您应该使用以下语法,前提是 delayed variable expansion 已禁用(这是默认设置)并且字符串存储在变量 _str:

cmd /V /D /C echo(!_str!| findstr /E /I "world"

这会在子 cmd 实例 (/V) 中启用延迟扩展,因此变量会尽可能晚地扩展,因此没有特殊字符会造成伤害。有害的SPACE当然在这里被忽略了。

echo 命令会导致管道启动一个新的 cmd 实例,因为 echo 是一个 cmd-内部命令,所以整体性能不是降级了。


通过 echo 通过管道传递多个字符串变得有点棘手,因为类似于:

(echo abc&echo def) | …

或:

(
    echo abc
    echo def
) | …

引入了额外的 SPACEs,这是将此类命令块转换为单个命令行的结果,因此也将换行符替换为 & 符号。例如,对于前一个示例,命令 echo 如下所示:

(echo abc  & echo def )  | …

然而,有一种方法,即包括转义的符号,按字面意思:

(echo abc^& rem/ & echo def^& rem/) | …

或:

(
    echo abc^& rem/
    echo def^& rem/
) | …

rem/命令只是一个无害且被忽略的注释,/确保后续命令不被视为注释而是按预期执行。

当然这一切都可以结合cmd /V /D /C如上所示