来自文件中各行的值

时间:2015-01-10 18:43:07

标签: shell

structureA在文件中多次出现,我必须在numUnitsA,numUnitsB,numUnitsC下分别对参数1的值求和,以解决所有出现的结构A.

structureA {
    numUnitsA {
        parameter1 = 2
    }    
    numUnitsB {
        parameter1 = 4
    }    
    numUnitsC {
        parameter1 = 3
    }    
} 

我使用下面的内容来获取值,但是如何将它们相加如下:

numUnitsA parameter1=6
numUnitsB parameter1=9
numUnitsC parameter1=9

代码:

while read -r line
do
if grep -q "parameter1" "$filename"; then
   echo $(awk 'BEGIN{FS="="}{print $2}' )
fi
done < "$filename"

1 个答案:

答案 0 :(得分:1)

试试这个:

awk -F'= *' '/parameter1/ {
    if (++numUnit % 3 == 1) {par1 += $2}
    else if (numUnit % 3 == 2) {par2 += $2}
    else {par3 += $2}
}
END {print "numUnitsA parameter1=" par1
     print "numUnitsA parameter1=" par2
     print "numUnitsA parameter1=" par3}' "$filename"

没有理由循环。这将把文件作为参数并查找“numUnitX”的出现,获取下一行并将值添加到与X对应的总值。最后它将打印总数。

替代回答:

$ cols=$(($(grep parameter1 $filename | wc -l)/3))
$ grep parameter1 "$filename" | sed 's/.*= //' | pr -ts"+" --columns "$cols" | bc

这将得到所有值,然后将单位A,B和C值彼此相邻地粘贴在单独的行上,用“+”分隔,并使用bc计算总和。输出为三行,分别包含单元A,B和C的总数。

<强>更新 如果参数不紧跟numUnits标记,则现在可以回答。

<强>解释

awk 是一个将文件划分为记录的程序(将它们视为行,即使它们可以是多行)和字段(将这些视为列,前一条注释仍然有效)。这些记录和字段的分离可以由用户定义,但默认分隔符是记录的换行符和字段的选项卡。所以文件结构定义如下:

record1: field1    field2 spaces allowed    field 3
record2: this record has only one field

record4: the previous line was an empty record
record5: in awk you can refer to fields using $1, $2, $3. like this:
$1 in your code means this field    $2 in code this field    $3    $4
record7: $0 is the variable for the entire record!

可以使用$1$2等来处理字段,特殊$0指的是整个记录。两个简单的例子来说明。首先我们打印整个文件,使脚本等同于catawk '{print} file' or awk'{print $ 0}'文件. A second example changes every record (i.e. line as default) to the literal string不要模拟awk : awk'{$ 0 =“don'\''mock awk”}'file . Note the special care to output a'`。

Builtins 我们可以使用一些强大的awk内置变量,其中一些变量如下所述。

  • FS字段分隔符,默认为FS = "\t"
  • RS记录分隔符,默认为RS = "\n"
  • OFS输出字段分隔符,默认为OFS = " "
  • ORS输出记录分隔符,默认为ORS = "\n"
  • NR当前记录编号,最后是文件中的记录数。
  • NF此记录中的字段数。
  • FILENAME正在处理的文件的文件名。

这些是非常有用的变量,当打印输出字段时,将自动插入分隔符OFS。下面的示例代码打印第一行的前两个字段,由单个空格分隔(OFS通过使用空格插入)。 awk 'NR == 1 {print $1, $2}' file

结构基本的awk结构如下:

awk -F'= ' '
# this is a comment (starting with #)
# begin clause
BEGIN {
    # do stuff BEFORE parsing the file
    FS = "= +"    # this is also achieved using the -F flag above
    ... 
}
/some regex/ {
    # code here will be executed if record contains 'some regex'
    # example: count number of lines that match this regex
    count++   # increment count with one
}
NR == 1 {
    # code here will only be executed on the first record
}
{
    # code right here will always be executed (i.e. for every record)
    # note the regex is missing => match every record
    ...
}
# add more clauses to match certain records before the end clause:
END {
    # execute code AFTER all files (you can read multiple files) have been parsed
    print count   # print number of records containing our regex
}' path/to/some/file_to_parse /another/path/to/another/file

如果前面的布尔值返回true,无论是在记录中找到正则表达式(/regex notation/)还是逻辑比较,基本上都会执行用大括号括起来的代码。当条件不足时,代码将始终执行。

分析了解决方案代码

如您所见,我们没有BEGIN子句,只有一个记录子句。我们正在寻找包含文字字符串'parameter1'的记录,行。这正是包含我们想要总结的值的行。

我们已将字段分隔符设置为正则表达式= +,表示等号和一个或多个空格。请注意,对于我们感兴趣的记录,这意味着我们有两条记录:

        paramter1 = 4
      field1     |||field 2,

这意味着$2现在指的是4。请注意,$2在以下记录中为空:paramter1=4,因为等号后没有空格。

现在我们有一个案例转换:

  1. numUnit相当于1 modulo 3
  2. numUnit相当于2 modulo 3
  3. numUnit相当于3 modulo 3.
  4. 请注意,我们首先使用if (++numUnit ...,这将在计算表达式之前增加变量numUnit(因此在if检查条件之前)。如您所见,awk没有强类型,因此无需先声明numUnit。在第一次增加时,awk会假设它为零,因为你试图添加一些东西而且他不知道它是什么。

    每次我们找到包含numUnit的记录时,paramter1都会增加。由于第一次将numUnit计算为1,然后遵循模式1 2 0 1 2 0 ...'并且'numUnit'模式为numUnitA numUnitB numUnitC numUnitA numUnitB ...,您可以看到每个案例都处理所有且仅有一种类型的记录。现在每个案例都会将参数的值添加到它的总数中(现在您可以在代码中轻松看到)。

    最后,我们通过打印信息来结束awk脚本,请记住,只有在读完所有记录后才会执行一次。这应该是清楚的。

    我强烈建议阅读awk,它是一种非常强大的脚本语言,允许许多高级编程语言结构。一开始看起来似乎很难,但这完全值得付出努力!