Windows批处理文件从文件中提取几行并对特定列中的值求和

时间:2013-07-10 19:06:32

标签: regex windows batch-file cmd text-processing

我这里有一个文件file1.txt,内容将是这样的

013A Not Visible            ???:? 09C:DB  2-Way Mir     N/Grp'd      RW       3     
013B Not Visible            ???:? 07A:DB  2-Way Mir     N/Grp'd      RW       3     
013C Not Visible            ???:? 08B:DB  2-Way Mir     N/Grp'd      RW       3          
0242 Not Visible            ???:? 10D:D3  RAID-5        N/Grp'd  (M) RW   43163     
0246 Not Visible            ???:? 10A:CB  RAID-5        N/Grp'd  (M) RW   43163     
024E Not Visible            ???:? 09D:D4  RAID-5        N/Grp'd  (M) RW   43163     
02A6 Not Visible            ???:? 06B:C8  RAID-5        N/Grp'd  (M) RW   43163         
09A8 Not Visible            ???:? 07C:D1  RAID-6        N/Grp'd  (M) RW   43163     
09AA Not Visible            ???:? 09D:C1  RAID-6        N/Grp'd  (M) RW   43163     
09AC Not Visible            ???:? 09A:C2  RAID-6        N/Grp'd  (M) RW   43163     
09B0 Not Visible            ???:? 08B:C0  RAID-6        N/Grp'd  (M) RW   43163 

我的任务是在上面用粗体字母显示的列中搜索单词,并获得每个类别的最后一列中的数字总和。

在上面的示例中我有3组单词

  1. 2-Way Mir
  2. RAID-5
  3. RAID-6
  4. 所以我需要总结最后一列。对于2-Way Mir,总和为3+3+3= 9
    如何使用批处理文件收集相同的内容?

    实际间距:

3 个答案:

答案 0 :(得分:1)

GNU代码

>awk "{a[$6]+=$NF} END {for (x in a) print x,a[x]}" file
RAID-5 172652
2-Way 9
RAID-6 172652

为方便起见,请将Mir添加到2-WayDownload here

答案 1 :(得分:0)

@ECHO OFF
SETLOCAL
FOR %%i IN (mir2 raid5 raid6) DO SET /a %%i=0
FOR /f "delims=" %%i IN (file1.txt) DO CALL :process %%i
ECHO 2-Way Mir : %mir2%
ECHO RAID-5    : %raid5%
ECHO RAID-6    : %raid6%
GOTO :EOF
:process
SET "line=%*"
:loop
SET value=%2
IF DEFINED value shift&GOTO loop
SET line=%line:~38,9%
IF /i "%line%"=="2-way mir" SET /a mir2+=%1
IF /i "%line%"=="RAID-5   " SET /a raid5+=%1
IF /i "%line%"=="RAID-6   " SET /a raid6+=%1
GOTO :EOF

应该为你做的工作。我假设围绕键串的星号是尝试使这些字符串变粗的失败。我还假设数据采用固定列格式。实际上,如果确实如此,可能会有更简单的方法:

@ECHO OFF
SETLOCAL
FOR %%i IN (mir2 raid5 raid6) DO SET /a %%i=0
FOR /f "delims=" %%i IN (file1.txt) DO CALL :process %%i
ECHO 2-Way Mir : %mir2%
ECHO RAID-5    : %raid5%
ECHO RAID-6    : %raid6%
GOTO :EOF
:process
SET "line=%*"
IF /i "%line:~38,9%"=="2-way mir" SET /a mir2+=%line:~70%
IF /i "%line:~38,9%"=="RAID-5   " SET /a raid5+=%line:~70%
IF /i "%line:~38,9%"=="RAID-6   " SET /a raid6+=%line:~70%
GOTO :EOF 

如果需要可以进一步简化。请注意,9语句中的if长度必须匹配,而/i会使if不区分大小写。


扩展匹配 - 稍微复杂一些,但会自动调整......

@ECHO OFF
SETLOCAL
FOR /f "delims==" %%i IN ('set $ 2^>nul') DO SET "%%i="
SET maps="2-way mir" "RAID-5   "
SET maps=%maps% "RAID-6   "

SET strcnt=0
FOR %%i IN (%maps%) DO CALL :setup %%i
FOR /f "delims=" %%i IN (file1.txt) DO CALL :process %%i
SET mapnbr=1
:ploop
CALL ECHO %%$_%mapnbr%%% : %%$%mapnbr%%%
SET /a mapnbr+=1
IF %mapnbr% leq %strcnt% GOTO ploop
GOTO :EOF
:process
SET "line=%*"
SET mapnbr=%strcnt%
:matchloop
CALL SET match=%%$_%mapnbr%%%
IF /i "%line:~38,9%"==%match% CALL SET /a $%mapnbr%+=%line:~70%&GOTO :eof
SET /a mapnbr-=1
IF %mapnbr% neq 0 GOTO matchloop
GOTO :EOF

:: Set $n=0 & $_n=string-to-match
:setup
SET /a strcnt+=1
SET /a $%strcnt%=0
SET    $_%strcnt%=%1
GOTO :eof

基本上,变量$n包含要在引号中匹配的字符串$_n。只需将带引号的9个字符的字符串添加到带有空格或逗号分隔符的maps中。

答案 2 :(得分:0)

批量数学限制使得如果任何总和超过2147483647,则无法创建合理的纯批处理解决方案。可以编写复杂的例程来批量执行大量计算,但我不认为它们是合理的。

假设所有总和都小于允许的最大值,则以下解决方案有效。

如果你的“单词”不包含空格,这将会容易得多。通常,环境变量可以在名称中包含空格。但SET / A选项不支持变量名中的空格。因此,需要一组额外的映射变量来将每个唯一的“单词”映射到不包含空格的变量名称。如果“单词”从不包含空格,则运行总和可以简单地存储在直接从“单词”派生的变量中。

@echo off
setlocal enableDelayedExpansion

:: Define input file
set "file=file1.txt"

:: Clear any existing $ variables and initialize unique "word" count
for /f "delims==" %%V in ('2^>nul set $') do set "%%V="
set "cnt=0"

:: Iteratively read each line in the file
for /f "usebackq delims=" %%A in ("%file%") do (

  %= Extract the correct "word" (%%N) from the line by position =%
  set "ln=%%A"
  for /f "delims=" %%N in ("!ln:~42,13!") do (

    %= If this is a new "word", then setup mapping =%
    if not defined $%%N (
      set /a cnt+=1        %= Increment unique "word" count     =%
      set "$%%N=!cnt!"     %= Map "word" to an "array" position =%
      set "name!cnt!=%%N"  %= Store "word" in name "array"      =%
    )

    %= Extract the value from line by position and add it to =%
    %= the appropriate array element by using the $word map  =%
    set /a "val!$%%N!+=!ln:~71!"
  )
)

:: Iterate the "arrays" and print results
for /l %%N in (1 1 %cnt%) do echo !name%%N!  !val%%N!

注意:上面的代码使用环境变量名称约定来模拟数组。批处理没有真正的数组。

以下是file1.txt中的示例数据的结果:

2-Way Mir      9
RAID-5         172652
RAID-6         172652