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"
答案 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
指的是整个记录。两个简单的例子来说明。首先我们打印整个文件,使脚本等同于cat
:awk '{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
,因为等号后没有空格。
现在我们有一个案例转换:
numUnit
相当于1 modulo 3 numUnit
相当于2 modulo 3 numUnit
相当于3 modulo 3. 请注意,我们首先使用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,它是一种非常强大的脚本语言,允许许多高级编程语言结构。一开始看起来似乎很难,但这完全值得付出努力!