FINDSTR和REGEX返回的数字超出了我的需要

时间:2017-03-22 19:57:36

标签: regex batch-file

我需要 $uid 只返回我指定的数字,比如FINDSTR,而不是2等等。但我的代码会循环显示以我指定的数字开头的任何数字。如果我指定20, 21, 22, 200, 201, 202,则会抓取1313

为什么正则表达式130 - 139会返回FINDSTR /b /r /c:"13[^0-9]" elabs.txt13

我的代码:

130 - 139

源文件中的示例文本:

@echo off
setlocal enabledelayedexpansion enableextensions

set "_RunlistName=ELabs.tab"
set /p "Begin=Begin is:"
set /p "End=end is:"

:forloop
REM Find event time and convert to seconds, then output start time and time between two runs into new config file.
For /F "tokens=1,2,3,4 delims=-:." %%a in ('Findstr /B /R /C:"%Begin%[^0-9]" !_RunlistName!') do (
    set /A "hr1=1%%b-100, min1=1%%c-100, sec1=1%%d-100"
    set /A "BS=(hr1 * 3600) + (min1 * 60) + sec1"
    )
For /F "tokens=1,2,3,4 delims=-:." %%a in ('Findstr /B /R /C:"%End%[^0-9]" !_RunlistName!') do (
    set /A "hr2=1%%b-100, min2=1%%c-100, sec2=1%%d-100"
    set /A "ES=(hr2 * 3600) + (min2 * 60) + sec2"
    )

REM For testing...
set /A "delta=ES-BS"
Echo delta = !ES! - !BS! = !delta! 
echo.
echo begin=!begin!, !hr1!:!min1!:!sec1!
Echo end=!end!, !hr2!:!min2!:!sec2!
pause

endlocal
exit /B

3 个答案:

答案 0 :(得分:2)

遵循this套规则,您的问题是延迟扩展阶段正在填充^正在执行的命令中的for /f字符。加倍^(一个插入符将被消除以逃避另一个插入符号)或从命令中删除延迟变量扩展阶段。

使用(保持延迟扩展,双重插入符号)

For /F "tokens=1,2,3,4 delims=-:." %%a in ('
    Findstr /B /R /C:"%Begin%[^^0-9]" !_RunlistName!
') do (

或(保持插入,删除延迟扩展)

For /F "tokens=1,2,3,4 delims=-:." %%a in ('
    Findstr /B /R /C:"%Begin%[^0-9]" %_RunlistName%
') do (

答案 1 :(得分:1)

命令

%SystemRoot%\System32\findstr.exe /B /R /C:"13[^0-9]" ELabs.tab

工作并输出以13开头的行,并忽略以130开头至13913001399的行,... < / p>

此命令在 FOR 循环中用作执行 STDOUT 的输出应由 FOR 捕获和处理的命令在后台的另一个命令进程中隐式运行此命令行。

但在命令行之前

Findstr /B /R /C:"%Begin%[^0-9]" !_RunlistName!

在后台命令进程中使用%SystemRoot%\System32\cmd.exe /c执行,执行批处理文件的命令进程将对其进行两次解析。

在执行完整 FOR 命令块之前已完成首次解析时,环境变量引用%Begin%将替换为输入的数字13。插入符号^保留在此解析步骤中。因此,在运行 FOR 之前,稍后执行的命令行将变为例如

Findstr /B /R /C:"13[0-9]" !_RunlistName!

但由于!_RunlistName!引用了具有延迟扩展的环境变量_RunlistName,因此在另一个命令进程中执行命令行之前,会立即再次解析此命令行。在第二个解析步骤^被解释为转义字符,因此被删除。因此,后台命令进程以命令行

启动
C:\Windows\System32\cmd.exe /c Findstr /B /R /C:"13[0-9]" ELabs.tab

FINDSTR 找到的行现在不再正确了,因为^在字符类定义中应该表示 NOT 之前被解释为转义字符,因此删除它会改变正则表达式的含义。

一种解决方案是在 FOR 命令行中使用:

Findstr /B /R /C:"%Begin%[^0-9]" %_RunlistName%

通过使用%_RunlistName%,执行批处理文件的命令进程没有第二个解析步骤,因此稍后将使用插入符继续运行此命令行,例如

C:\Windows\System32\cmd.exe /c Findstr /B /R /C:"13[0-9]" ELabs.tab

第二种解决方案是使用另一个插入符号来逃避插入符号,即使用

Findstr /B /R /C:"%Begin%[^^0-9]" !_RunlistName!

这也会导致执行 FINDSTR ,例如/C:"13[^0-9]"

这两个解决方案也由MC ND提供。

另一种解决方案是在 FOR 命令行中使用:

Findstr /B /R /C:"%Begin%\>" %_RunlistName%

\>表示在帮助输出中通过在命令提示符窗口中运行findstr /?来解释单词的结尾。由于搜索到的号码必须在一行的开头找到,因此使用\>会导致只找到两行以两个输入的数字开头。

如何找出批处理文件执行的内容?

有一个很棒的免费Windows Sysinternals工具Process Monitor

下载ZIP文件并将文件解压缩到具有管理员权限的"%ProgramFiles%\Sysinternals"或具有当前用户权限的"%USERPROFILE%\Desktop\Sysinternals"等任何本地目录后,必须使用Procmon.exe >以管理员身份运行。

首次启动Microsoft提供的免费工具时,必须接受许可协议。

然后打开 Process Monitor Filter 对话框,建议调查此批处理文件执行以添加两个过滤器:

  1. 流程名称 cmd.exe ,然后包含,然后点击按钮添加
  2. 流程名称 findstr.exe ,然后包含,然后点击按钮添加
  3. 接下来,应该看一下工具栏右侧的最后5个符号,这些符号表示并单击切换一般显示过滤器的状态。带有工具提示显示文件系统活动的文件柜符号应作为唯一启用,因为只需显示文件系统活动即可调查此批处理过程。

    按Ctrl + X或单击工具栏左侧的第五个符号以清除已制作的记录,并在命令提示符窗口中执行批处理文件(首选调试批处理文件)或双击批处理文件。

    批处理文件执行完毕并且输入焦点重新开启 Process Monitor 后,按Ctrl + E或单击工具栏左侧的第三个符号以停止捕获,这需要几秒钟。

    现在查看记录。批处理文件使用具有特定 PID (进程标识符)的进程cmd.exe执行。

    在向下滚动时,可以看到突然又有一个进程cmd.exe具有不同的 PID 。这是为运行 FINDSTR 命令行而执行的后台命令进程。

    在第二个cmd.exe上点击第二个(右)鼠标按钮以打开上下文菜单(主要(左))后,可以看到用于启动第二个cmd.exe进程的命令行鼠标按钮单击第一个上下文菜单项属性,主要(左)鼠标按钮单击选项卡处理

    在批处理文件中使用Findstr /B /R /C:"%Begin%[^0-9]" !_RunlistName!并为13输入Begin时,命令行为:

    C:\Windows\system32\cmd.exe /c Findstr /B /R /C:"13[0-9]" ELabs.tab
    

    这清楚地说明在执行 FINDSTR 的后台命令进程之前已经从命令行中删除了插入符号。

    因此,在这种情况下,进程findstr.exe的命令行就不足为奇了:

    Findstr /B /R /C:"13[0-9]" ELabs.tab
    

    按照建议修改批处理文件并在每次使用Ctrl + X清除 Process Monitor 日志并使用Ctrl + E再次捕获后再运行它,可以看到后台命令如何处理执行 FOR 命令行中指定的命令行实际上已执行,导致最终使用正确的参数执行 FINDSTR

    免费进程监视器确实是一个很好的工具,可以找出应用程序或脚本出现意外行为的原因。

答案 2 :(得分:1)

无论如何,我很难理解findstr的必要性。

For /F "UseBackQ Tokens=1,3,4,5 Delims=-:. " %%a In ("%_RunlistName%") Do If "%%a"=="%Begin%" (...

For /F "UseBackQ Tokens=1,3,4,5 Delims=-:. " %%a In ("%_RunlistName%") Do If "%%a"=="%End%" (...