我在这里有一个文件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
我的任务是在上面用粗体字母显示的列中搜索单词,并获得每个类别最后一列中数字的总和。
在上面的例子中,我有三组单词
- 双向和平号
- RAID-5
- RAID-6
所以我需要对最后几列求和。对于2-Way Mir
,sum是3+3+3= 9
如何使用批处理文件收集相同的数据?
实际间距:
>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
如果需要,可以进一步简化。请注意,长度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
包含要在引号中匹配的字符串。只需在maps
中添加更多带引号的9个字符字符串,并使用空格或逗号分隔符即可。