【问题标题】:Converting lines in chunks into tab delimited将块中的行转换为制表符分隔
【发布时间】:2016-06-29 01:23:45
【问题描述】:

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

xox
91-233
chicago

koko
121-111
alabama

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

xox  91-233  chicago
koko 121-111 alabama

我该怎么做?

我尝试了tr "\n" "\t",但它并没有达到我想要的效果。

【问题讨论】:

    标签: csv awk sed newline


    【解决方案1】:
    $ awk -F'\n' '{$1=$1} 1' RS='\n\n' OFS='\t' file
    xox     91-233  chicago
    koko    121-111 alabama 
    

    工作原理

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

    • -F'\n'

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

    • $1=$1

      这告诉 awk 将第一个字段分配给第一个字段。虽然这似乎没有任何作用,但它会导致 awk 将记录视为已更改。因此,使用我们为 ORS 分配的值(输出记录分隔符)打印输出。

    • 1

      这是 awk 用于打印行的神秘简写。

    • RS='\n\n'

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

    • OFS='\t'

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

    【讨论】:

      【解决方案2】:

      此答案提供以下内容:
      * 它适用于任意大小的非空行块,由任意数量的空行分隔; John1024's helpful answer(类似并排在第一位)适用于由正好一个空行分隔的行块。
      * 详细解释了awk命令的使用。

      更惯用的(符合 POSIX 标准)awk 解决方案:

      awk -v RS= -F '\n' -v OFS='\t' '$1=$1""' file
      
      • -v RS= 告诉awk段落 模式下运行:将非空 行的每一行视为单个 记录; RS 是输入记录分隔符。

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

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

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

        • 尾随"" 是为了防止在数值上下文中评估为0 的段落中第一行的边缘情况;附加"" 会强制将其视为字符串,并且任何非空字符串——即使它包含"0"——在布尔上下文中都被视为true——见下文。李>
      • 1234563因为赋值被用作一个pattern(一个条件),并且一个非空字符串被认为是true,并且没有关联的action块( { ... }),隐含的操作打印 - 重建 - 输入记录,该记录现在由用制表符分隔的输入行组成,由默认输出记录分隔符 (ORS)、\n 终止。

      【讨论】:

        【解决方案3】:

        另一种选择,

        $ sed '/^$/d' file | pr -3ats$'\t'
        
        xox     91-233  chicago
        koko    121-111 alabama
        

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

        请注意,这仅适用于所有块大小相同的情况。

        【讨论】:

        • ++,但我建议对 pr 命令进行更易于理解的重新表述(pr 是一个用于 pagination 的复杂实用程序,在此处重新使用; pr 有很多选项,理解 man 页面并不简单):pr -3 -l 1 -s:一次读取 3 行输入,并将它们输出到单行 (-l 1),分隔 ( -s) 与默认分隔符 \t。 (顺便说一句:这通常不适用于 BSD pr(在 OS X 上找到),因为如果输入行的长度为8 - 1 的倍数)。
        【解决方案4】:
        xargs -L3 < filename.log |tr ' ' '\t'
        xox 91-233 chicago
        koko 121-111 alabama
        

        【讨论】:

        • ++ 一个简单的解决方案;为制表符分隔的输出添加| tr ' ' '\t'(根据OP的要求)。在推广此解决方案时有一些注意事项:(a) xargs 将“吃掉”未转义的 \ 字符。在输入和 (b) 行中,带有行内部空格的行将分别将其标准化为一个空格。 Quibble:使用-L3,因为-l 选项已被弃用。
        【解决方案5】:

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

         awk '{if(NF>0){a=a$1"\t";i++};if(i%3==0&&NF>0){print a;a=""}}' input_file
        

        【讨论】:

        • 这行得通(尽管您可能希望将块中的行数作为 变量 传递),但 (a) 只处理 first i> 每个输入行上的空格分隔字段(确实适用于 sample 数据,但值得指出作为一般约束)和 (b) 导致 尾随标签 i> 在每条输出线上 - 两者都可能接受也可能不接受。
        猜你喜欢
        • 2013-06-11
        • 1970-01-01
        • 1970-01-01
        • 2021-07-21
        • 2019-06-03
        • 1970-01-01
        • 2021-10-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多