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

前端 未结 4 600
时光取名叫无心
时光取名叫无心 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 08:51

    For the first part of the question, here is a one way to swap every other line with each other in sed without using regular expressions:

    sed -n 'h;n;p;g;p'
    

    The -n command line suppresses the automatic printing. Command h puts copies the current line from the pattern space to the hold space, n reads in the next line to the pattern space and p prints it; g copies the first line from the hold space back to the pattern space, bringing the first line back into the pattern space, and p prints it.

    0 讨论(0)
  • 2020-12-15 08:52

    First question:

    awk '{x = $0; getline; print; print x}' filename
    

    next question: sort by 2nd line

    paste - - < filename | sort -f -t $'\t' -k 2 | tr '\t' '\n'
    

    which outputs:

    dobroye utro!
    Good morning!
    annyonghaseyo
    hello
    watashi
    me
    
    0 讨论(0)
  • 2020-12-15 08:54
    sed 'N; 
    s/\(.*\)\n\(.*\)/\2\
    \1/' infile
    

    N - append the next line of input into the pattern space
    \(.*\)\n\(.*\) - save the matching parts of the pattern space the one before and the one after the newline.
    \2\\ \1 - exchange the two lines (\1 is the first saved part, \2 the second). Use escaped literal newline for portability

    With some sed implementations you could use the escape sequence \n: \2\n\1 instead.

    0 讨论(0)
  • 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/'
    
    0 讨论(0)
提交回复
热议问题