我一直在尝试弄清楚如何使用 awk 或 sed 将文本 block 中的第一行与该 block 中的所有其他行合并。每个 block 由 2 行或更多行组成,例如:
AA
1
BB
2
3
4
CC
5
6
7
8
如何将其合并到下面的输出中:
AA 1
BB 2
BB 3
BB 4
CC 5
CC 6
CC 7
CC 8
非常感谢任何帮助。
最佳答案
假设符合 POSIX 的 awk
和 shell*,这将起作用......
awk '/^[[:space:]]*$/ {a=""} {if (a=="") {a=$0} else print a,$0}'
其工作原理说明(更新):
有两个操作。第一个对空行(可选空格除外)使用react,因为它前面有以下模式:/^[[:space:]]*$/
。当然,斜线只是简单地界定模式。插入符号 (^
) 匹配行的开头,美元符号 ($
) 匹配行的结尾。这会强制匹配整行(否则,此模式将匹配任何行,因为每个可能的输入行都包含零个或多个空白字符)。 [[:space:]]*
匹配预定义的空白字符类中的零个或多个 (*
) 个字符。此模式的操作将变量(无意义地命名为 a
)重置为空字符串。这用于检测下一个文本 block 的开始。
第二个操作没有模式,因此对每个输入行执行一次。它检查是否已经设置了前缀(同样是变量 a
),并且:
- 如果没有,则会将前缀设置为当前行的内容 (
$0
)。 (请注意,这也会在空行上无用地执行。) - 如果有,则打印前缀,后跟当前行的内容。 (
awk
由于使用逗号而自动插入空格。)
讽刺的是,我在编写此更新时发现了一个错误:仅包含空格的行将被接受作为前缀。这是因为在这种情况下检查 if (a=="")
失败。有多种方法可以解决这个问题。我自己对 awk 的了解还不够,无法推荐特定的方法,但这似乎可以做到:
awk '/^[[:space:]]*$/ {s=1;a=""} {if (s==0 && a=="") a=$0; else print a,$0; s=0}'
*) 我最初(并且懒洋洋地)写了“GNU awk 和 bash”,只是因为那是我用于测试的东西。 Ed Morton 指出我的解决方案不使用任何 non-portable features然而。
关于awk - 将文本 block 中的第一行与 block 中的每一下一行合并,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54242508/