使用批处理文件提取特定行(基于行号)

时间:2014-07-30 11:46:13

标签: windows batch-file cmd findstr

我需要从文本文件(input.txt)中提取特定行。我已经找到了一个解决方案,但有一些说明,当它与setlocalenabledealyed expansion一起使用时,它无法正常工作。以下是示例

我的 input.txt (numbered using findstr /n)。在这个例子中,我需要提取行号27到39之间的行。在我的完整批处理文件中,这些值是从另一个模块调用的。

1:[root]
2:ASKEHPPTEQWEIRAZOKXL
...
...
...
27:[parent2/child2]
28:NJ35CG5D9DEYXKMQKBJX
29:ZAZRMGB2E0KAG85FSPI3
30:E9046AQL44LV1R79OT8E
31:8OPXV1QYCTQVK34JZ2KV
32:3E32PWHGX5RGTFUXI9GC
33:H7DTDDFQZVGETGL764YU
34:174UOQMW35BCIQJNR1P8
35:7B3V0E9QXFQOM3NF08CZ
36:QH6FZVMKKGHKF0J8PB5O
37:QCRC90QCWWGAHRWBVMUI
38:4QPVEJW75GFW8DUM1PGU
39:[parent2/child3]
...
...
...
3000:[end]

第一个代码 - calling.bat - 使用CALL

@echo OFF

set st_ln=27
set end_ln=39

for /f "tokens=1,2 delims=:" %%a in (input.txt) do call :extract "%%a" "%%b"
goto :eof

:extract
   set "ln=%~1"
   set "sid=%~2"
   if %ln% LEQ %st_ln% goto :eof
   if %ln% GEQ %end_ln% goto :eof
   echo.%sid%
   goto :eof

:eof

第二个代码 - local.bat setlocalenabledelayedexpansion

一起使用
REM @echo OFF

set st_ln=27
set end_ln=39

SETLOCAL ENABLEDELAYEDEXPANSION

for /f "tokens=1,2 delims=:" %%a in (input.txt) do (
   set "ln=%%a"
   set "sid=%%b"
   if !ln! LEQ !st_ln! goto :eof
   if !ln! GEQ !end_ln! goto :eof
   echo.!sid!
)

:eof

OUTPUT - Calling.bat 绝对正常。但是 local.bat 不会返回任何错误,但它只迭代for循环一次。 (我尝试用%st_ln%&%end_ln%替换!st_ln!&!end_ln!但仍然是同样的问题)为什么?我错过了什么?

C:\Temp>calling.bat
NJ35CG5D9DEYXKMQKBJX
ZAZRMGB2E0KAG85FSPI3
E9046AQL44LV1R79OT8E
8OPXV1QYCTQVK34JZ2KV
3E32PWHGX5RGTFUXI9GC
H7DTDDFQZVGETGL764YU
174UOQMW35BCIQJNR1P8
7B3V0E9QXFQOM3NF08CZ
QH6FZVMKKGHKF0J8PB5O
QCRC90QCWWGAHRWBVMUI
4QPVEJW75GFW8DUM1PGU

C:\Temp>local.bat

C:\Temp>REM @echo OFF

C:\Temp>set st_ln=27

C:\Temp>set end_ln=39

C:\Temp>SETLOCAL ENABLEDELAYEDEXPANSION

C:\Temp>for /F "tokens=1,2 delims=:" %a in (input.txt) do (
set "ln=%a"
 set "sid=%b"
 if !ln! LEQ !st_ln! goto :eof
 if !ln! GEQ !end_ln! goto :eof
 echo.!sid!
)

C:\Temp>(
set "ln=1"
 set "sid=[root]"
 if !ln! LEQ !st_ln! goto :eof
 if !ln! GEQ !end_ln! goto :eof
 echo.!sid!
)

C:\Temp>

补充问题:

正如我上面所说,我可以得到预期的结果,但只是想知道它是否可以增强。我想从输入文件中提取特定行(行可以是输入文件中的任何位置,行数可以是1到20),输入文件最多可以有3000行。目前在上面的代码中我使用for循环并检查每一行的行号,因此它将遍历for循环3000次,这可能会延迟输出。有没有其他方法可以避免这种情况并加快脚本速度(可能是findstr'range'搜索)?

1 个答案:

答案 0 :(得分:2)

你的local.bat不起作用,因为当第一行被重新编号时,编号为1,并且第27行开始,条件if !ln! LEQ !st_ln! goto :eof被评估为真并执行了goto命令,离开for循环。

对于补充问题,您可以计算在文件开头需要跳过的行数,然后只处理直到到达结束行。由于循环内没有变量变化,因此不需要延迟扩展

set /a "skipLines=st_ln-1"
if %skipLines% gtr 0 ( 
    set "skipLines=skip=%skipLines%" 
) else ( 
    set "skipLines=" 
)


for /f "%skipLines% tokens=1,2 delims=:" %%a in (input.txt
) do if %%a gtr %end_ln% ( goto :eof ) else ( 
    echo(%%b
)

if %skiplines% gtr 0测试是必要的,因为for /f循环不允许skip=0子句

相关问题