首页 > 解决方案 > 解析多行程序输出

问题描述

我最近一直在做一些实验室任务,为了很好地收集和分析结果,我准备了一个 bash 脚本来自动化我的工作。这是我第一次尝试创建这样的脚本,因此它并不完美,我的问题与改进它密切相关。

该程序的示例输出如下所示,但我想让它更通用以用于更多目的。

>>> VARIANT 1 <<<
Random number generator seed is 0xea3495cc76b34acc
Generate matrix 128 x 128 (16 KiB)
Performing 1024 random walks of 4096 steps.
> Total instructions: 170620482
> Instructions per cycle: 3.386
Time elapsed: 0.042127 seconds
Walks accrued elements worth: 534351478

我想收集的所有数据总是在不同的行中。我的第一次尝试是运行同一个程序两次(或更多次,具体取决于数据量),然后在每次运行中使用 grep 通过查找关键字来提取我需要的数据。这是非常低效的,因为可能有一些可能解析一次运行的整个输出,但我想不出任何想法。目前脚本是:

#!/bin/bash
write() {
    o1=$(./progname args | grep "Time" | grep -o -E '[0-9]+.[0-9]+')
    o2=$(./progname args | grep "cycle" | grep -o -E '[0-9]+.[0-9]+')
    o3=$(./progname args | grep "Total" | grep -o -E '[0-9]+.[0-9]+')
    echo "$1    $o1   $o2     $o3"
}

for ((i = 1; i <= 10; i++)); do
    write $i >> times.dat
done

值得一提的是,echo在一行中生成结果至关重要,因为我稍后使用 gnuplot 并且在列中包含数据非常适合该用途。样本输出应为:

1    0.019306   3.369     170620476
2    0.019559   3.375     170620475
3    0.021971   3.334     170620478
4    0.020536   3.378     170620480
5    0.019692   3.390     170620475
6    0.020833   3.375     170620477
7    0.019951   3.450     170620477
8    0.019417   3.381     170620476
9    0.020105   3.374     170620476
10    0.020255   3.402     170620475

我的问题是:如何改进脚本以仅在一次程序执行中收集此类数据?

标签: bashawk

解决方案


您可以awk在此处使用并将值放入数组中,然后通过 index 访问它们,1以防您想在单个命令中执行此操作。23

myarr=($(your_program args | awk '/Total/{print $NF;next} /cycle/{print $NF;next}  /Time/{print $(NF-1)}'))

或使用以下命令将所有元素强制打印到一行中,如果有人使用"它来保持新行对值的安全,则不会出现新行。

myarr=($(your_program args | awk '/Total/{val=$NF;next} /cycle/{val=(val?val OFS:"")$NF;next}  /Time/{print val OFS $(NF-1)}'))

说明:添加awk上述程序的详细说明。

awk '              ##Starting awk program from here.
/Total/{           ##Checking if a line has Total keyword in it then do following.
  print $NF        ##Printing last field of that line which has Total in it here.
  next             ##next keyword will skip all further statements from here.
}
/cycle/{           ##Checking if a line has cycle in it then do following.
  print $NF        ##Printing last field of that line which has cycle in it here.
  next             ##next keyword will skip all further statements from here.
}
/Time/{            ##Checking if a line has Time in it then do following.
  print $(NF-1)    ##Printing 2nd last field of that line which has Time in it here.
}'

要访问您可以使用的单个项目,例如:

echo ${myarr[0]},echo ${myarr[1]}echo ${myarr[2]},Totalcycle分别time

如果需要,通过循环访问所有元素的示例:

for i in "${myarr[@]}"
do
  echo $i
done

推荐阅读