将块中的行转换为制表符分隔

Converting lines in chunks into tab delimited

我在 2 个块中有以下几行(实际上有 ~10K)。 在此示例中,每个块包含 3 行。块由空行分隔。所以这些块就像“段落”。

xox
91-233
chicago

koko
121-111
alabama

我想把它变成制表符分隔的行,像这样:

xox  91-233  chicago
koko 121-111 alabama

我该怎么做?

我尝试了 tr "\n" "\t",但它没有达到我的要求。

$ awk -F'\n' '{=} 1' RS='\n\n' OFS='\t' file
xox     91-233  chicago
koko    121-111 alabama 

工作原理

Awk 将输入分成记录,并将每条记录分成字段。

  • -F'\n'

    这告诉 awk 使用换行符作为字段分隔符。

  • =

    这告诉 awk 将第一个字段分配给第一个字段。虽然这似乎什么都不做,但它会导致 awk 将记录视为已更改。因此,使用我们为 ORS 分配的值打印输出,输出记录分隔符。

  • 1

    这是 awk 的神秘 shorthand 打印行。

  • RS='\n\n'

    这告诉 awk 将两个连续的换行符视为记录分隔符。

  • OFS='\t'

    这告诉 awk 在输出时使用制表符作为字段分隔符。

另一种选择,

$ sed '/^$/d' file | pr -3ats$'\t'

xox     91-233  chicago
koko    121-111 alabama

使用 sed 删除空行并使用制表符分隔符打印到 3 列。在您的真实文件中,这应该是块中的行数。

请注意,这仅在所有块的大小相同时才有效。

此答案提供以下内容:
* 它适用于由任意数量的空行分隔的任意大小的非空行块; (相似且排在第一位)处理由 恰好一个 空行分隔的行块。
* 详细解释了awk命令的使用。

更惯用(POSIX 兼容)awk 解决方案:

awk -v RS= -F '\n' -v OFS='\t' '=""' file
  • -v RS= 告诉 awk 段落 模式下运行:考虑 的每个 运行 nonempty 单个 记录; RS是输入记录分隔符。

    • 注意:这意味着该解决方案将一个或更多个空行视为分隔段落(行块); empty 表示:根本没有行内部字符,甚至没有空格。
  • -F '\n' 告诉 awk 将输入段落的每一行视为其自己的字段(将多行输入记录按行分成多个字段); -F设置FS,输入字段分隔符

  • -v OFS='\t' 告诉 awkoutput 上用 \t(制表符)分隔字段; OFS 是输出字段分隔符。

  • ="" 看起来像空操作,但是,由于 分配给字段变量 </code> (记录的第一个字段), 告诉 <code>awk 重建 输入记录,使用 OFS 作为字段分隔符,从而有效地将 \n 分隔符替换为 \t.

    • 结尾的 "" 是为了防止在数字上下文中评估为 0 的段落中第一行的边缘情况;附加 "" 强制处理为 字符串 ,并且任何非空字符串 - 即使它包含 "0" - 都被视为 true在布尔上下文中 - 见下文。
  • 鉴于 </code> 根据定义 <em>nonempty</em> 并且鉴于 <code>awk 中的赋值传递它们的值,赋值的结果="" 也是一个非空字符串;因为赋值被用作 pattern(条件),并且非空字符串被认为是 true,并且没有关联的 action block ({ ... }), implied actionprint - rebuilt - input record, which现在由用 制表符分隔的输入行组成 ,由默认输出记录分隔符 (ORS)、\n.

    [=96= 终止]

另一个版本的 awk 可以做到这一点

 awk '{if(NF>0){a=a"\t";i++};if(i%3==0&&NF>0){print a;a=""}}' input_file
xargs -L3 < filename.log |tr ' ' '\t'
xox 91-233 chicago
koko 121-111 alabama