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



我在这里有一个文件file1.txt,内容将类似于这个

013A不可见??:?09C:DB 2路Mir N/Grp’d RW 3013B不可见??:?07A:DB双向Mir N/Grp’d RW 3013C不可见??:?08B:DB 2路Mir N/Grp’d RW 30242不可见??:?10D:D3 RAID-5 N/Grp’d(M)RW 431630246不可见??:?10A:CB RAID-5 N/Grp’d(M)RW 43163024E不可见??:?09D:D4 RAID-5 N/Grp’d(M)RW 4316302A6不可见??:?06B:C8 RAID-5 N/Grp’d(M)RW 4316309A8不可见??:?07C:D1 RAID-6 N/Grp’d(M)RW 4316309AA不可见??:?09D:C1 RAID-6 N/Grp’d(M)RW 4316309AC不可见??:?09A:C2 RAID-6 N/Grp’d(M)RW 4316309B0不可见??:?08B:C0 RAID-6 N/Grp’d(M)RW 43163

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

在上面的例子中,我有三组单词

  1. 双向和平号
  2. RAID-5
  3. RAID-6

所以我需要对最后几列求和。对于2-Way Mir,sum是3+3+3= 9
如何使用批处理文件收集相同的数据?

实际间距:

GNU awk代码:
>awk"{a[$6]+=$NF}END{for(x in a)print x,a[x]}"文件袭击-5 172652双向9突袭-6 172652

请将Mir添加到2-Way以方便您
在此处下载

如果任何总和超过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!

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

以下是文件1.text:中示例数据的结果

2-Way Mir      9
RAID-5         172652
RAID-6         172652
@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 

如果需要,可以进一步简化。请注意,长度9if语句中必须匹配,而/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包含要在引号中匹配的字符串。只需在maps中添加更多带引号的9个字符字符串,并使用空格或逗号分隔符即可。

最新更新