【问题标题】:How can I combine odd and even numbered lines?如何组合奇数和偶数行?
【发布时间】:2021-03-04 22:00:18
【问题描述】:

我想将每个偶数行与它上面的行合并。比如:

第一行,csv,csv,csv
第二行,csv,csv
第三行,csv,csv,csv,csv
第四行,csv

结果应该是这样的:

第一行,csv,csv,csv,第二行,csv,csv
第三行,csv,csv,csv,csv,第四行,csv

任何想法如何在 Perl 或 sed/awk 中实现这一目标?

【问题讨论】:

    标签: text


    【解决方案1】:

    在这里,使用 sed:

    sed '$!N;s/\n/,/'
    

    和 awk:

    awk '{if (e) {print p","$0;} else {p=$0;} e=!e;}'
    

    awk 'NR%2==0 {print p","$0;} NR%2 {p=$0;}'
    

    【讨论】:

    • perl -pe '$|--||s!$/!,!'还要短!
    • @mob, $. % 2 &&$|-- || 一样短,但没有那么特别。
    • 我喜欢这个 sed 选项,而且速度很快。有人可以解释一下“$!”是什么吗?在序列的开始呢? 'N;s/\n/,/' 似乎得到了几乎相同的结果。
    • @PieterMüller 在序列的开头不需要$!,因为如果seds Nn 命令尝试读取超出文件末尾的内容,它们将终止任何进一步的命令.但是,如果未设置 -n 选项,它仍会打印模式空间。
    • 不适用于 ubuntu。只需连接从第一行结束的位置开始的第二行中的字符。
    【解决方案2】:

    这就是paste 命令的用途。假设你的输出是用command 生成的,那么你可以这样做:

    $ command | paste -d, - -
    

    或者如果输出存储在文件中

    $ paste -d, - - <file.csv
    

    例子:

    paste -d, - - <<END
    Line one,csv,csv,csv
    Line two,csv,csv
    Line three,csv,csv,csv,csv
    Line four,csv
    END
    

    输出:

    Line one,csv,csv,csv,Line two,csv,csv
    Line three,csv,csv,csv,csv,Line four,csv
    

    【讨论】:

    • 没听说过 paste,我不清楚 process_to_produce_output 应该是什么来解决这个问题。更多细节?
    • 粘贴的 (Solaris) 手册页为 here。问题本身并没有说明输入是如何产生的。它是文件还是其他进程的输出?
    • 非常感谢您提供的链接,我的 Cygwin 手册页的帮助要小得多。
    • 在cygwin上,info paste会给你一个教程。
    • paste 将文件行合并在一起,使用默认的 TAB 分隔符。如果您将- 指定为文件,它会将其解释为STDIN。所以paste -d, - - 的意思是:合并来自STDIN 和STDIN 的行,使用, 作为分隔符而不是TAB。如果你使用paste -d, - - -,它将每3行连接在一起,- - - -将每4行连接在一起,依此类推。
    【解决方案3】:

    还有一个:

    awk -F, ORS=NR%2\?FS:RS infile
    

    您不需要引用 ?大多数shell

    【讨论】:

    • 这太棒了!
    【解决方案4】:

    Perl 的内置变量$. 会告诉你行号。如果$. 为奇数,$. % 2 将为1,否则为0。这是一个独立的示例;

    #!/usr/bin/perl
    
    use strict; use warnings;
    
    my $buffer;
    
    while (my $line = <DATA>) {
        if ($. % 2) {
            chomp $line;
            $buffer = $line;
        }
        else {
            print join(",", $buffer, $line);
        }
    }
    
    __DATA__
    Line one,csv,csv,csv
    Line two,csv,csv
    Line three,csv,csv,csv,csv
    Line four,csv
    

    输出:

    C:\Temp> tt
    第一行,csv,csv,csv,第二行,csv,csv
    第三行,csv,csv,csv,csv,第四行,csv

    【讨论】:

      【解决方案5】:

      通常,您会在缓冲区中累积数据,直到您知道要输出什么,然后再输出数据。

      my @buf;
      while (<>) {
          chomp;
          if (!@buf) {
             push @buf, $_;
             next;
          }
      
          my $line1 = shift(@buf);
          my $line2 = $_;
          print("$line1,$line2\n");
      }
      

      但在这种情况下,存在一个更简单的解决方案,因为您的问题可以重述为:用逗号替换每个第二个换行符,从第一个换行符开始。

      perl -pe's/\n/,/ if $. % 2' file
      

      【讨论】:

        【解决方案6】:

        一个稍微简单的 Perl 解决方案。

        #!/usr/bin/perl
        
        use strict;
        use warnings;
        
        while (<DATA>) {
          chomp;
          print "$_," . <DATA>;
        }
        
        __DATA__
        Line one,csv,csv,csv
        Line two,csv,csv
        Line three,csv,csv,csv,csv
        Line four,csv
        

        【讨论】:

          【解决方案7】:

          你不需要像 perl/sed/awk 这样的核武器来解决这个问题。 xargs 就够了。

          xargs -d '\n' -n2
          

          测试

          kent$  echo "Line one,csv,csv,csv
          Line two,csv,csv
          Line three,csv,csv,csv,csv
          Line four,csv"|xargs -d '\n' -n2
          Line one,csv,csv,csv Line two,csv,csv
          Line three,csv,csv,csv,csv Line four,csv
          

          【讨论】:

          • 好吧,如果你不关心尾随 cvsLine 之间缺少的 FS :)
          • xargs -n2 ('\n' 是 -d 选项的默认值)的工作原理都是一样的,看起来很容易记住。添加到我的收藏中的一个不错的技巧。谢谢
          猜你喜欢
          • 2019-06-27
          • 2020-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多