批处理Windows中的正则表达式

时间:2018-11-15 03:23:43

标签: regex batch-file

我目前正在做一个批处理作业(我也是这个新手)来获取Maven依赖项列表。 一直在使用正则表达式来获取这些依赖项,但无济于事。我已经在此site上测试了我的正则表达式,看来它正在工作。

stackoverflow question处的FOR循环中检查了所需的转义字符,但再次失败了,因此我不得不在这里寻求帮助。

有关我的代码段esp,请参见下文。正则表达式部分,外部循环很好。

for /f "tokens=*" %%i in ('findstr "+- \\-"  dependency-list.txt') do (
    for /f "tokens=*" %%j in ('findstr /i /r "^^(.+^)\[:\]^(.+^)^(:jar:^)^(.+^)^(:compile^)" %%i') do (
        echo %%j
    )
)

这是从我的外循环中获取的示例数据:

[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile
[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile
[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile

我只想使用正则表达式来获得这些部分:

commons-configuration:commons-configuration:jar:1.5:compile
org.owasp.esapi:esapi:jar:2.0.1:compile
commons-lang:commons-lang:jar:2.3:compile

这些是我尝试执行批处理脚本时遇到的错误。

FINDSTR: Cannot open org.owasp.esapi:esapi:jar:2.0.1:compile
'+-' is not recognized as an internal or external command,
operable program or batch file.
| was unexpected at this time.

任何帮助将不胜感激。

注意: 一旦我能够成功执行我的正则表达式,就可以删除外部循环。

1 个答案:

答案 0 :(得分:0)

FINDSTR 的正则​​表达式功能非常有限,因为可以在打开命令提示符窗口并运行findstr /?来获取其帮助时进行读取。 FINDSTR 的正则​​表达式功能与Perl compatible regular expressionsBoost.Regex或其他Perl语法中的正则表达式实现相距甚远。

没有任何选项可用于仅通过正则表达式匹配的字符串通过 FINDSTR 获得输出。有几个选项可控制 FINDSTR 的输出,但没有一个选项仅用于输出找到的字符串。

因此,有必要使用另一种方法删除文件+-中包含\-dependency-list.txt的处理行上剩余感兴趣数据的所有内容。 Windows命令处理器仅提供两个用于字符串重新格式化任务的命令: FOR SET

下面的批处理文件演示了这两个文件,其中考虑到访问同一命令块中定义/修改的环境变量的值需要延迟扩展。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
cls
set "DeleteExample="
if exist dependency-list.txt goto GetData
(
    set "DeleteExample=1"
    echo First line with no data of interest.
    echo [INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile
    echo [INFO] ^|  +- commons-configuration:commons-configuration:jar:1.5:compile
    echo [INFO] ^|  ^|  +- commons-lang:commons-lang:jar:2.3:compile
    echo ;[INFO]^|  \- commons-lang:commons-lang:jar:4.5:compile
    echo Line trailing space at end +- 
    echo Line with no space at end  +-
    echo Line with just a hyphen character - somewhere on line.
    echo [INFO] ^|  ^|  +- !commons-configuration!:commons-configuration!:jar:5.2:compile
    echo Last line with no data of interest.
)>dependency-list.txt

:GetData
echo First solution
echo ==============
echo/
setlocal EnableDelayedExpansion
for /F "tokens=*" %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt 2^>nul') do (
    echo Line read: "%%I"
    set "Line=%%I"
    set "Line=!Line:*- =!"
    if defined Line echo Line work: "!Line!"
    rem More commands working with environment variable Line referenced with
    rem exclamation marks for delayed expansion on execution of the command line.
)
endlocal

echo/
echo Second solution
echo ===============
echo/
for /F "tokens=1* delims=-" %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt') do (
    if not "%%J" == "" (
        echo Line read: "%%J"
        set "Line=%%J"
        setlocal EnableDelayedExpansion
        call set "Line=%%Line:~1%%"
        if defined Line call echo Line work: "%%Line%%"
        rem More commands working with environment variable Line referenced
        rem with two percent signs on both side and with using command CALL.
        endlocal
    )
)

echo/
echo Third solution
echo ==============
echo/
for /F "tokens=1* delims=-" %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt 2^>nul') do (
    if not "%%J" == "" (
        echo Line read: "%%J"
        for /F "tokens=*" %%L in ("%%J") do if not "%%L" == "" (
            echo Line work: "%%L"
            rem More commands working with loop variable L.
        )
    )
)

echo/
echo Fourth solution
echo ===============
echo/
for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt 2^>nul') do (
    echo Line read: "%%I"
    set "Line=%%I"
    setlocal EnableDelayedExpansion
    set "Line=!Line:*- =!"
    if defined Line echo Line work: "!Line!"
    rem More commands working with environment variable Line referenced with
    rem exclamation marks for delayed expansion on execution of the command line.
    endlocal
)

echo/
echo Fifth solution
echo ==============
echo/
for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /L /C:+- /C:"\\-" dependency-list.txt') do (
    echo Line read: "%%I"
    set "Line=%%I"
    call :ProcessLine
)
goto EndDemo

:ProcessLine
set "Line=%Line:*- =%"
if defined Line echo Line work: "%Line%"
rem More commands working with environment variable Line referenced with
rem percent signs for expansion before execution of the command line.
goto :EOF

:EndDemo
if defined DeleteExample del dependency-list.txt
echo/
endlocal
pause

此批处理文件的输出为:

First solution
==============

Line read: "[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: "[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: "[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: "Line trailing space at end +- "
Line read: "Line with no space at end  +-"
Line work: "Line with no space at end  +-"
Line read: "[INFO] |  |  +- :commons-configuration:jar:5.2:compile"
Line work: ":commons-configuration:jar:5.2:compile"

Second solution
===============

Line read: " org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: " commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: " commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: " "
Line read: " !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

Third solution
==============

Line read: " org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: " commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: " commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: " "
Line read: " !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

Fourth solution
===============

Line read: "[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: "[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: "[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: ";[INFO]|  \- commons-lang:commons-lang:jar:4.5:compile"
Line work: "commons-lang:commons-lang:jar:4.5:compile"
Line read: "Line trailing space at end +- "
Line read: "Line with no space at end  +-"
Line work: "Line with no space at end  +-"
Line read: "[INFO] |  |  +- !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

Fifth solution
==============

Line read: "[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: "[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: "[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: ";[INFO]|  \- commons-lang:commons-lang:jar:4.5:compile"
Line work: "commons-lang:commons-lang:jar:4.5:compile"
Line read: "Line trailing space at end +- "
Line read: "Line with no space at end  +-"
Line work: "Line with no space at end  +-"
Line read: "[INFO] |  |  +- !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

前四个解决方案在单独的命令过程中运行,该过程以cmd.exe /C开始,并在命令行的后台运行:

C:\Windows\System32\findstr.exe /R "+- \\-" dependency-list.txt

此命令行导致在当前目录中搜索文件dependency-list.txt,该文件可能与批处理文件的目录不同,使用区分大小写的正则表达式查找包含+-或{{1}的行}。

第五种解决方案在单独的命令行中运行命令行:

\-

此命令行查找相同的行,但是使用区分大小写的文字搜索来查找包含C:\Windows\System32\findstr.exe /L /C:+- /C:"\\-" dependency-list.txt +-的行。

FINDSTR 在找不到包含\-或{{1的任何行时,不会向 STDOUT 输出任何内容,也不会向 STDERR 输出任何内容}}。

FOR 将输出捕获到单独命令过程的 STDOUT 并逐行处理输出。

空行会被 FOR 忽略,因为默认情况下,由于分行字符选项的默认设置是+-,所以也以分号开头的行。 FOR 默认情况下使用常规空格和水平制表符作为字符串定界符,将该行拆分为子字符串(令牌),并仅将第一个空格/制表符分隔的字符串分配给指定的循环变量。

第一个解决方案

第一个解决方案通过使用选项\-来修改 FOR 的行处理行为,这会导致删除行中的所有前导空格/制表符,并且如果还有剩余的内容分配给其余行,行,其中包含到指定循环变量eol=;的空格/制表符。以tokens=*开头的输出中的行显示了 FOR 处理后分配给循环变量I的字符串。

此字符串已分配给环境变量Line read:。然后,使用命令 SET 进行字符串替换,并使用延迟的环境变量扩展(根据引用环境值的要求),从行中删除直到首次出现的由连字符和空格组成的字符串为止的所有内容在命令块中以I开头并以匹配的Line结尾的变量中定义/修改的变量。

如果在字符串替换后还剩下一些东西,导致仍然定义了环境变量(,则该行的剩余部分将与)输出,以查看字符串替换的作用。

此解决方案速度很快,但缺点是 FOR 会忽略以分号开头的行,并且永久启用的延迟环境变量扩展会导致包含不正确处理的一个或多个感叹号的行。但是,这是文件Line上的最佳解决方案,永远不会包含以Line work:开头并包含一个或多个dependency-list.txt的感兴趣的行。

第二个解决方案

第二种解决方案使用命令 FOR 将不以分号开头的每个非空行拆分为两个子字符串。根据{{​​3}}表,将直到一个或多个;首次出现的第一个子字符串分配给指定的循环变量!,并将其余行分配给下一个循环变量-

因此,对于示例行I包含感兴趣的数据,并在开头不是空字符串的情况下使用前导空格。再次使用命令 SET 将前导空格删除,然后将其分配给环境变量J,最后仅分配从第二个字符开始的字符串,该第二个字符的字符索引为1,直到字符串的结尾。

但不是使用延迟扩展,而是通过引用之前在命令块中设置的环境变量值(两侧带有两个百分号)并使用命令 CALL 来强制{{3 }}第二次执行命令 SET ECHO 之前的两行。因此,在执行 FOR 之前解析整个命令块时,使用 CALL 的两行代码变为:

J

由于命令 CALL ,第二次在循环的每次迭代中解析这两行,导致用当前字符串分别替换Linecall set "Line=%Line:~1%" if defined Line call echo Line work: %Line% 而没有第一个字符在执行%Line:~1%%Line%之前。

此解决方案正确处理了包含感叹号的目标行,因为避免了使用延迟扩展。

第三种解决方案

第三种解决方案类似于第二种解决方案。它使用第二个 FOR 从外部 FOR 分配给循环变量set的字符串中删除所有前导空格/制表符,并将其余字符串分配给循环变量{ {1}},甚至可以是一个空字符串。

由于速度更快,该解决方案绝对比第二种解决方案好。

第四种解决方案

编写这四个解决方案时,始终将捕获的输出中的整个非空行分配给循环变量echo,而与第一个字符是哪个字符无关。通过定义一个空的定界符列表可以禁用行拆分行为,并且可以使用无行结束符的定义来禁用忽略以特定字符开头的行。

删除字符串,直到第一个连字符和空格第一次出现,就像在第一个解决方案中一样。区别在于延迟扩展在将行分配给环境变量J时被禁用,而下一个临时被启用以处理行字符串。

此解决方案的缺点是循环内的命令LI不仅可以启用和禁用延迟扩展,还可以执行更多操作。有关命令 SETLOCAL ENDLOCAL 的详细信息,请参见ASCII。因此,此解决方案绝对不是所提供解决方案中最快的解决方案。

第五种解决方法

第五种解决方案与第四种解决方案相似,不同之处在于它展示了一种通用技术,该技术可避免使用 FOR 循环内的子程序通过在 strong> FOR 循环。

该解决方案的速度也很慢,但是具有一个很大的优势,即在批处理文件中顶部Line的情况下运行批处理文件时,调试起来很容易。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • setlocal EnableDelayedExpansion
  • endlocal
  • @echo ON
  • call /?
  • cls /?
  • del /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • pause /?