如何使用bash脚本拆分包含多个记录的行

3

我有一个这样的文件:

Heading1 Heading2 A1 A2 B1 B2 
Heading3 Heading4 A3 A4 B3 B4 C1 C2

每一行都包含多个属于相同标题的记录。我试图做的是拆分这些记录并保留它们的标题。在上面的示例中,我想生成以下内容:

Heading1 Heading2 A1 A2
Heading1 Heading2 B1 B2 
Heading3 Heading4 A3 A4
Heading3 Heading4 B3 B4
Heading3 Heading4 C1 C2

我的主要问题是每行记录数不固定。

编辑:每行有2个标题和N个记录,每个记录用2个字段表示。因此,每行的长度为2+2*N。所以它始终是偶数。


1
这行代码 Heading1 Heading2 A1 A2 B1 B2 A3 应该如何处理? - RomanPerekhrest
你是什么意思? - Mewtwo
我的意思是:字段的数量可能是奇数吗?3、5、7、9? - RomanPerekhrest
抱歉我之前没提到,那是很重要的。每一行都有两个标题和N个记录,每个记录用两个字段表示。所以字段长度的一般形式为2+2*N。因此它始终是偶数。 - Mewtwo
4个回答

3

简短的awk解决方案:

awk '{ for(i=3;i<=NF;i+=2) print $1,$2,$i,$(i+1) }' file

输出结果:
Heading1 Heading2 A1 A2
Heading1 Heading2 B1 B2
Heading3 Heading4 A3 A4
Heading3 Heading4 B3 B4
Heading3 Heading4 C1 C2
  • for(i=3;i<=NF;i+=2) - 循环遍历从第三个字段开始的所有字段(i+=2 - 成对迭代)

非常好!谢谢。 - Mewtwo

1
awk '{for(i=3;i<=NF;i+=2)print $1,$2,$i,$(i+1)}' file

NF表示行中的字段数,$i表示您可以使用第 i 个字段。


12秒的差异(再次) - RomanPerekhrest
damn :D recapthca appeared - tso

0
这是一个纯 Bash 的解决方案:
#!/bin/bash

while read -r; do
    read -r h1 h2 rest <<< "$REPLY"
    while [ -n "$rest" ]; do
        read -r x1 x2 rest <<< "$rest"
        printf '%s %s %s %s\n' "$h1" "$h2" "$x1" "$x2"
    done
done

@EdMorton 这对我的回答有什么影响(除了性能,因为在这个例子中已经有其他使用awk的答案了)? - melpomene
我不知道它是否存在其他问题,但它的编写长度更长且执行速度比awk慢,因此没有理由考虑它,因为提问者已经标记了她的问题为awk,所以我们知道awk解决方案(在所有方面都比嵌套的shell循环更好)是可接受的。这只是你不应该做的事情。 - Ed Morton
另一方面,问题标题说“使用bash脚本”。如果我们要追求速度,Perl解决方案不是更好吗?@EdMorton - melpomene
1
随意发布一个Perl解决方案。 它与awk解决方案(反之亦然)相比不会明显更快,但至少这是值得考虑的合理选择,尽管OP可能没有可用的perl,因为它不像awk那样在所有UNIX安装中都作为标准提供。 通常,当人们谈论bash / shell脚本时,他们只是指包括sed和awk等标准UNIX工具,他们并不是指仅使用shell内置命令。 - Ed Morton
1
@EdMorton 好的,没问题。 - melpomene

0

使用GNU sed:

sed -E 's/^(([^ ]* ){2})(([^ ]* ){2})/\1\3\n\1/;P;D;' file

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接