How to switch/rotate every two lines with sed/awk?

前端 未结 4 630
时光取名叫无心
时光取名叫无心 2020-12-15 08:47

I have been doing this by hand and I just can\'t do it anymore-- I have thousands of lines and I think this is a job for sed or awk.

Essentially, we have a file lik

4条回答
  •  南笙
    南笙 (楼主)
    2020-12-15 09:03

    Assuming an input file like this:

    A sentence X
    Z matching sentence Y
    A sentence Z
    B matching sentence N
    A sentence Z
    M matching sentence N
    

    You could do both exchange and sort with Perl:

    perl -lne'
     $_{ $_ } = $v unless $. % 2;
     $v = $_;
     END {
      print $_, $/, $_{ $_ }
        for sort keys %_; 
       }' infile
    

    The output I get is:

    % perl -lne'
     $_{ $_ } = $v unless $. % 2;
     $v = $_;
     END {
      print $_, $/, $_{ $_ }
        for sort keys %_;
       }' infile
    B matching sentence N
    A sentence Z
    M matching sentence N
    A sentence Z
    Z matching sentence Y
    A sentence X
    

    If you want to order by the first line (before the exchange):

    perl -lne'
     $_{ $_ } = $v unless $. % 2;
     $v = $_;
     END {
      print $_, $/, $_{ $_ }
        for sort {
          $_{ $a } cmp $_{ $b }
          } keys %_; 
       }' infile
    

    So, if the original file looks like this:

    % cat infile1
    me
    watashi 
    hello
    annyonghaseyo
    Good morning!
    dobroye utro!
    

    The output should look like this:

    % perl -lne'
     $_{ $_ } = $v unless $. % 2;
     $v = $_;
     END {
      print $_, $/, $_{ $_ }
        for sort {
      $_{ $a } cmp $_{ $b }
      } keys %_;
       }' infile1
    dobroye utro!
    Good morning!
    annyonghaseyo
    hello
    watashi 
    me
    

    This version should handle duplicate records correctly:

    perl -lne'
     $_{ $_, $. } = $v unless $. % 2;
     $v = $_;
     END {
        print substr( $_, 0, length() - 1) , $/, $_{ $_ }
        for sort {
          $_{ $a } cmp $_{ $b }
          } keys %_; 
       }' infile
    

    And another version, inspired by the solution posted by Glenn (record exchange included and assuming the pattern _ZZ_ is not present in the text file):

    sed 'N; 
      s/\(.*\)\n\(.*\)/\1_ZZ_\2/' infile | 
        sort |
          sed 's/\(.*\)_ZZ_\(.*\)/\2\
    \1/'
    

提交回复
热议问题