文件中各行的总和值
Sum values from various lines in a file
structureA 在一个文件中多次出现,我必须在 numUnitsA、numUnitsB、numUnitsC 下分别对 structureA 的所有出现的参数 1 的值求和。
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 }' )
fi
done < "$filename"
试试这个:
awk -F'= *' '/parameter1/ {
if (++numUnit % 3 == 1) {par1 += }
else if (numUnit % 3 == 2) {par2 += }
else {par3 += }
}
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 , , . like this:
in your code means this field in code this field
record7: [=12=] is the variable for the entire record!
字段可以用</code>、<code>
等方式寻址,特殊的[=19=]
指的是整条记录。举两个简单的例子来说明。首先我们打印整个文件,渲染脚本等同于 cat
:awk '{print} file' or
awk '{print $0}' file. A second example changes every record (i.e. line as default) to the literal string
don't mock awk:
awk '{$0 = "don'\'' mock awk"}' 文件. Note the special care to output a
'`.
Builtins 一些强大的 awk 内置变量可供我们使用,其中一些解释如下。
FS
字段分隔符,默认FS = "\t"
RS
记录分隔符,默认RS = "\n"
OFS
输出字段分隔符,默认OFS = " "
ORS
输出记录分隔符,默认ORS = "\n"
NR
当前记录数,最后是文件中的记录数
NF
这条记录中的字段数。
FILENAME
正在处理的文件的文件名。
这些都是非常有用的变量,打印输出时字段分隔符OFS
会自动插入。以下示例代码打印第一行的前两个字段,由单个 space 分隔(使用 space 插入 OFS
)。 awk 'NR == 1 {print , }' 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
基本上,如果前面的布尔值 returns 为真,则执行大括号中的代码,无论它是在记录中找到的正则表达式 (/regex notation/
) 还是逻辑比较。当缺少条件时,代码将始终执行。
解析代码
如您所见,我们没有 BEGIN 子句,只有一个记录子句。我们正在寻找记录,在我们的例子中是行,包含文字字符串 'parameter1'。这正是包含我们想要总结的值的行。
我们将字段分隔符设置为正则表达式 = +
,意思是一个等号和一个或多个 space。请注意,对于我们感兴趣的记录,这意味着我们有两条记录:
paramter1 = 4
field1 |||field 2,
这意味着 </code> 现在指的是 <code>4
。请注意,</code> 在以下记录中将为空:<code>paramter1=4
因为等号后没有 space。
现在我们有一个案例的转换:
numUnit
等于 1 模 3
numUnit
等于 2 模 3
numUnit
等于 3 模 3.
请注意,我们首先有 if (++numUnit ...
,这将在计算表达式之前增加变量 numUnit
(因此在 if 检查条件之前)。如您所见,awk 不是强类型的,因此无需先声明 numUnit
。在第一次增加时,awk 会假设它是一个零,因为你试图向它添加一些东西,但他不知道它是什么。
因此,每当我们找到包含 paramter1
的记录时,numUnit
就会增加。由于第一次 numUnit
被评估为 1,然后遵循模式 1 2 0 1 2 0 ...' 并且“numUnit”模式是 numUnitA numUnitB numUnitC numUnitA numUnitB ...
,您可以看到这些情况中的每一个都处理所有且只有一种类型的记录。每个案例现在都会将参数的值添加到它的总数中(正如您现在可以在代码中轻松看到的那样)。
最后我们通过打印信息来结束 awk 脚本,记住这只会在所有记录都被读取后执行一次。这个应该清楚了。
我强烈建议继续阅读 awk,它是一种非常强大的脚本语言,允许许多高级编程语言构造。乍一看似乎很难,但完全值得付出努力!
structureA 在一个文件中多次出现,我必须在 numUnitsA、numUnitsB、numUnitsC 下分别对 structureA 的所有出现的参数 1 的值求和。
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 }' )
fi
done < "$filename"
试试这个:
awk -F'= *' '/parameter1/ {
if (++numUnit % 3 == 1) {par1 += }
else if (numUnit % 3 == 2) {par2 += }
else {par3 += }
}
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 , , . like this:
in your code means this field in code this field
record7: [=12=] is the variable for the entire record!
字段可以用</code>、<code>
等方式寻址,特殊的[=19=]
指的是整条记录。举两个简单的例子来说明。首先我们打印整个文件,渲染脚本等同于 cat
:awk '{print} file' or
awk '{print $0}' file. A second example changes every record (i.e. line as default) to the literal string
don't mock awk:
awk '{$0 = "don'\'' mock awk"}' 文件. Note the special care to output a
'`.
Builtins 一些强大的 awk 内置变量可供我们使用,其中一些解释如下。
FS
字段分隔符,默认FS = "\t"
RS
记录分隔符,默认RS = "\n"
OFS
输出字段分隔符,默认OFS = " "
ORS
输出记录分隔符,默认ORS = "\n"
NR
当前记录数,最后是文件中的记录数NF
这条记录中的字段数。FILENAME
正在处理的文件的文件名。
这些都是非常有用的变量,打印输出时字段分隔符OFS
会自动插入。以下示例代码打印第一行的前两个字段,由单个 space 分隔(使用 space 插入 OFS
)。 awk 'NR == 1 {print , }' 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
基本上,如果前面的布尔值 returns 为真,则执行大括号中的代码,无论它是在记录中找到的正则表达式 (/regex notation/
) 还是逻辑比较。当缺少条件时,代码将始终执行。
解析代码
如您所见,我们没有 BEGIN 子句,只有一个记录子句。我们正在寻找记录,在我们的例子中是行,包含文字字符串 'parameter1'。这正是包含我们想要总结的值的行。
我们将字段分隔符设置为正则表达式 = +
,意思是一个等号和一个或多个 space。请注意,对于我们感兴趣的记录,这意味着我们有两条记录:
paramter1 = 4
field1 |||field 2,
这意味着 </code> 现在指的是 <code>4
。请注意,</code> 在以下记录中将为空:<code>paramter1=4
因为等号后没有 space。
现在我们有一个案例的转换:
numUnit
等于 1 模 3numUnit
等于 2 模 3numUnit
等于 3 模 3.
请注意,我们首先有 if (++numUnit ...
,这将在计算表达式之前增加变量 numUnit
(因此在 if 检查条件之前)。如您所见,awk 不是强类型的,因此无需先声明 numUnit
。在第一次增加时,awk 会假设它是一个零,因为你试图向它添加一些东西,但他不知道它是什么。
因此,每当我们找到包含 paramter1
的记录时,numUnit
就会增加。由于第一次 numUnit
被评估为 1,然后遵循模式 1 2 0 1 2 0 ...' 并且“numUnit”模式是 numUnitA numUnitB numUnitC numUnitA numUnitB ...
,您可以看到这些情况中的每一个都处理所有且只有一种类型的记录。每个案例现在都会将参数的值添加到它的总数中(正如您现在可以在代码中轻松看到的那样)。
最后我们通过打印信息来结束 awk 脚本,记住这只会在所有记录都被读取后执行一次。这个应该清楚了。
我强烈建议继续阅读 awk,它是一种非常强大的脚本语言,允许许多高级编程语言构造。乍一看似乎很难,但完全值得付出努力!