我需要 $uid
只返回我指定的数字,比如FINDSTR
,而不是2
等等。但我的代码会循环显示以我指定的数字开头的任何数字。如果我指定20, 21, 22, 200, 201, 202
,则会抓取13
和13
。
为什么正则表达式130 - 139
会返回FINDSTR /b /r /c:"13[^0-9]" elabs.txt
和13
?
我的代码:
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
答案 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
开头至139
,1300
至1399
的行,... < / 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 对话框,建议调查此批处理文件执行以添加两个过滤器:
接下来,应该看一下工具栏右侧的最后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%" (...