从文件中的一行中提取属性值

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"