从文件中的一行中提取属性值
Extract values of attribute from a line in file
我有一个包含多个属性的单行大文件(只有一行)。文件类似于 XML 但无效 XML,因此不确定是否可以使用 XML 实用程序。该行如下所示:
<a="1" b="2" time="10" c="3" time="1" time="3" d="1" e="1" f="1" time="10" .... />
我想提取所有时间值并求和。 time
可以是行中的任何位置。 GNU grep 不可用,因此无法使用 grep -oP
有人可以帮我 bash script/command 吗?
您可以使用 Perl 提取 time="..."
中的数字并将它们相加:
perl -pne 'use List::Util qw(reduce); $_ = reduce { $a + $b } /time="(\d+)"/g' < file
诀窍是 Perl 中的 /.../
运算符 returns 捕获组中的值列表。
在此示例中,time="..."
.
中的值
List::Util::reduce
就是计算它们的总和
中的-ne
是将stdin
的内容读入到$_
变量中,
而 -p
是自动打印 $_
变量的值(我们将其替换为值的总和)。
awk
怎么样?
awk 'BEGIN {RS=" "; FS="\""; sum=0} /time*/{sum+=} END {print sum}' data.xml
解释:
RS
代表记录分隔符,所以我们让awk
处理一对key=value一次。
FS
代表字段分隔符,所以我们用"
分割记录,方便提取数值[=34] =]
/time*/{sum+=}
将匹配任何以 time 开头的记录,并将该值添加到我们的全局 sum
.
- 在程序结束时,我们只打印在
sum
中累积的值。
这里不需要 GNU grep -P
:
grep -o 'time="[^"]*"' infile | cut -d '"' -f2 | paste -s -d+ | bc
这将提取所有 time="dd"
字符串:
time="10"
time="1"
time="3"
time="10"
cut
以"
为分隔符然后提取第二个字段,即数字:
10
1
3
10
paste -s -d+
将所有内容放回一行,使用 +
作为分隔符:
10+1+3+10
和bc
计算结果:
21
如果你的 grep 甚至没有 -o
选项,我刚刚意识到 POSIX 和 AIX grep 中都没有,你可以做类似
tr ' ' '\n' < infile | grep 'time=' | cut -d '"' -f2 | paste -s -d+ | bc
首先将每个 key/value 对放在单独的行上。这应该适用于具有这些实用程序的 POSIX 符合版本的任何系统。
有趣的总结。您也可以单独使用 grep -ow
和 bash。注意:要使其符合 POSIX shell,您需要将 grep
表达式的输出通过管道传输到 read
而不是使用 进程替换 . (并使用 sum="${sum}+$n"
而不是 +=
变体)您可以执行以下操作:
$ c=0; sum=; \
while read -r n; do \
((c > 0)) && sum+="+$n" || sum="$n"; ((c++)); \
done < <(grep -ow "[0-9]*" yourfile); \
echo $((sum)))
33
将其添加到组合中。如果您理解了所有的答案,您将有更多的工具可以添加到您的 shell 工具箱中。
输入文件
$ cat yourfile
a="1" b="2" time="10" c="3" time="1" time="3" d="1" e="1" f="1" time="10"
我有一个包含多个属性的单行大文件(只有一行)。文件类似于 XML 但无效 XML,因此不确定是否可以使用 XML 实用程序。该行如下所示:
<a="1" b="2" time="10" c="3" time="1" time="3" d="1" e="1" f="1" time="10" .... />
我想提取所有时间值并求和。 time
可以是行中的任何位置。 GNU grep 不可用,因此无法使用 grep -oP
有人可以帮我 bash script/command 吗?
您可以使用 Perl 提取 time="..."
中的数字并将它们相加:
perl -pne 'use List::Util qw(reduce); $_ = reduce { $a + $b } /time="(\d+)"/g' < file
诀窍是 Perl 中的 /.../
运算符 returns 捕获组中的值列表。
在此示例中,time="..."
.
List::Util::reduce
就是计算它们的总和
中的-ne
是将stdin
的内容读入到$_
变量中,
而 -p
是自动打印 $_
变量的值(我们将其替换为值的总和)。
awk
怎么样?
awk 'BEGIN {RS=" "; FS="\""; sum=0} /time*/{sum+=} END {print sum}' data.xml
解释:
RS
代表记录分隔符,所以我们让awk
处理一对key=value一次。FS
代表字段分隔符,所以我们用"
分割记录,方便提取数值[=34] =]/time*/{sum+=}
将匹配任何以 time 开头的记录,并将该值添加到我们的全局sum
.- 在程序结束时,我们只打印在
sum
中累积的值。
这里不需要 GNU grep -P
:
grep -o 'time="[^"]*"' infile | cut -d '"' -f2 | paste -s -d+ | bc
这将提取所有 time="dd"
字符串:
time="10"
time="1"
time="3"
time="10"
cut
以"
为分隔符然后提取第二个字段,即数字:
10
1
3
10
paste -s -d+
将所有内容放回一行,使用 +
作为分隔符:
10+1+3+10
和bc
计算结果:
21
如果你的 grep 甚至没有 -o
选项,我刚刚意识到 POSIX 和 AIX grep 中都没有,你可以做类似
tr ' ' '\n' < infile | grep 'time=' | cut -d '"' -f2 | paste -s -d+ | bc
首先将每个 key/value 对放在单独的行上。这应该适用于具有这些实用程序的 POSIX 符合版本的任何系统。
有趣的总结。您也可以单独使用 grep -ow
和 bash。注意:要使其符合 POSIX shell,您需要将 grep
表达式的输出通过管道传输到 read
而不是使用 进程替换 . (并使用 sum="${sum}+$n"
而不是 +=
变体)您可以执行以下操作:
$ c=0; sum=; \
while read -r n; do \
((c > 0)) && sum+="+$n" || sum="$n"; ((c++)); \
done < <(grep -ow "[0-9]*" yourfile); \
echo $((sum)))
33
将其添加到组合中。如果您理解了所有的答案,您将有更多的工具可以添加到您的 shell 工具箱中。
输入文件
$ cat yourfile
a="1" b="2" time="10" c="3" time="1" time="3" d="1" e="1" f="1" time="10"