从批处理文件中打印特定行

时间:2015-08-24 17:32:57

标签: batch-file

我正在尝试从文本文件中打印第4行,第21-50行,这可以在Windows下以某种方式完成吗?我一直在尝试这样做:

FOR /F "usebackq tokens=1 delims=-" %G IN (%COMPUTERNAME%.txt) DO ECHO %G

这只是非常糟糕。我不能只打印一组特定的线条吗?

我需要在多台计算机上运行此脚本,理想情况下我想将其转换为变量以便与slmgr -ipk一起使用,也许有人有更好的建议?

文本文件的内容(我想要XXXXX-XXXXX-XXXXX-XXXXX-XXXXX部分):

==================================================
Product Name      : Windows 7 Professional
Product ID        : 00371-OEM-9044632-95844
Product Key       : XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
Installation Folder : C:\Windows
Service Pack      : Service Pack 1
Computer Name     : LIBRA
Modified Time     : 6/4/2015 7:26:54 PM
==================================================

2 个答案:

答案 0 :(得分:1)

如果您只想要"产品密钥"你可以试试

type %COMPUTERNAME%.txt|find /i "Product Key"

for /f "tokens=2 delims=:" %%# in (' type %COMPUTERNAME%.txt^|find /i "Product Key"') do echo %%#

答案 1 :(得分:1)

对于手头的任务,npocmaka's answer是最合适的方法,因为它不会坚持要从文件中提取字符串的固定位置。
但是,我想提供一个坚持某个位置的变体。

以下代码提取放置在文件list.txt的第4行的第21行到第50列的字符串(结果被回显(包含在""中)并存储在变量LINE_TXT中(不带""):

@echo off

for /F "tokens=1,* delims=:" %%L in (
  'findstr /N /R ".*" "list.txt"'
) do (
  if %%L equ 4 (
    set "LINE_TXT=%%M"
    goto :NEXT
  )
)
:NEXT
if defined LINE_TXT set "LINE_TXT=%LINE_TXT:~20,29%"
echo."%LINE_TXT%"

goto :NEXT命令终止给定行的for /F循环;这不是强制性的,但会提高大型文件的性能(只要给定的行号非常小)。

为了更灵活,可以使用以下代码(在初始set块中定义字符串位置):

@echo off

rem Define the string position here:
set FILE_TXT="list.txt"
set LINE_NUM=4
set COL_FROM=21
set COL_UPTO=50

setlocal EnableDelayedExpansion
set /A COL_UPTO-=COL_FROM
set /A COL_FROM-=1
for /F "tokens=1,* delims=:" %%L in (
  'findstr /N /R ".*" %FILE_TXT%'
) do (
  if %%L equ %LINE_NUM% (
    set "LINE_TXT=%%M"
    if defined LINE_TXT (
      set "LINE_TXT=!LINE_TXT:~%COL_FROM%,%COL_UPTO%!"
    )
    goto :NEXT
  )
)
:NEXT
endlocal & set "LINE_TXT=%LINE_TXT%"
echo."%LINE_TXT%"

以上两个代码片段都依赖于findstr /N /R ".*"的输出,它返回与正则表达式.*匹配的每一行,表示零个或多个字符,而每个行实际上都是如此在文件中;但是,开关/N定义为每行添加其行号,我将其提取并与最初定义的行进行比较。

这是另一种变体,它使用for /F直接遍历给定文本文件的内容(行),而不使用findstr

@echo off

for /F "usebackq skip=3 eol== delims=" %%L in (
  "list.txt"
) do (
  set "LINE_TXT=%%L"
  goto :NEXT
)
:NEXT
if defined LINE_TXT set "LINE_TXT=%LINE_TXT:~20,29%"
echo."%LINE_TXT%"

此方法具有更好的性能,因为有skip选项跳过解析并迭代感兴趣的行(4)之前的所有行(1到3),而不是{{1变种。
但是,有一个缺点: findstring具有for /F选项,用于定义解释为行注释的字符(默认为eol);只要;没有定义分隔符(选项字符串中的最后一个位置),就无法关闭此选项,这在此处必须按原样返回该行;所以你必须找到一个在任何一行中都不是第一个的字符(我在这里定义了delims=,因为你的示例文本文件仅使用它作为页眉/页脚字符。)

要从第1行提取字符串,请删除=选项,因为skip会导致语法错误。

请注意,此处需要skip=0;否则,将提取文件的最后一行(非空)。

虽然goto :NEXT不会迭代文件中的任何空行,但这里没有问题,因为for /F选项不会检查行内容并跳过空行。

最后,这是使用skip的另一种方法,其中不进行文本解析。但是,此处需要一个临时文件将所需行的文本传递给变量more +3

LINE_TXT

此方法避免了@echo off set LINE_TXT= more +3 "list.txt" > "list.tmp" set /P LINE_TXT= < "list.tmp" del /Q "list.tmp" if defined LINE_TXT set "LINE_TXT=%LINE_TXT:~20,29%" echo."%LINE_TXT%" exit /B 0 ,因此避免了上述解决方案中提到的不需要的for /F选项的问题。但这并没有正确处理标签,因为eol用空格替换它们(默认情况下有8个缩进空格,可由more开关配置,其中/Tn是空格数。)