awk - 将文本 block 中的第一行与 block 中的每一下一行合并

标签 awk sed

我一直在尝试弄清楚如何使用 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/

相关文章:

file - 比较两个文件并输出两个文件的差异(包括行号和内容)

character-encoding - 如何使用awk读取不同编码的文件?

regex - 使用用户指定的替换字符串进行 sed 替换

linux|awk|shell脚本修改多个 block 中的同名行

bash - Shell脚本将矩形文本旋转45°

awk - 如何在gawk中指定文件前缀

python - 获取重复的行和文件的其余部分 [大文件 50G]

regex - 奇怪的 sed 行为

linux - 将文本附加到特定文件夹下的所有文件

c# - 正则表达式 - 通过注意缺少字符串然后插入它来匹配多行 block