如何使用sed / awk切换/旋转每两行?

时间:2011-07-25 15:15:28

标签: regex sed awk

我一直在手工做这个,我不能再做了 - 我有几千行,我认为这是sed或awk的工作。

基本上,我们有一个这样的文件:

A sentence X
A matching sentence Y
A sentence Z
A matching sentence N

此模式将继续整个文件。我想翻转每个句子和匹配的句子,这样整个文件最终会像:

A matching sentence Y
A sentence X
A matching sentence N
A sentence Z

任何提示?

编辑:扩展初始问题

Dimitre Radoulov为最初的问题提供了一个很好的答案。这是主要问题的延伸 - 更多细节:

假设我们有一个有组织的文件(由于Dimitre给出的sed行,文件是有组织的)。但是,现在我想按字母顺序组织文件,但只使用第二行的语言(英语)。

watashi 
me
annyonghaseyo
hello
dobroye utro!
Good morning!

我想通过英文句子(每第2句)按字母顺序排列。鉴于上述输入,这应该是输出:

dobroye utro!
Good morning!
annyonghaseyo
hello
watashi
me 

4 个答案:

答案 0 :(得分:16)

对于问题的第一部分,这里是一种在sed中互换每一行而不使用正则表达式的方法:

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

-n命令行禁止自动打印。命令h将当前行从模式空间复制到保留空间,n读取模式空间的下一行,p打印它; g将第一行从保留空间复制回模式空间,将第一行重新放回模式空间,p将其打印出来。

答案 1 :(得分:9)

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

N - 将下一行输入附加到模式空间
\(.*\)\n\(.*\) - 保存模式空间的匹配部分 新线之前和之后的那一个 \2\\ \1 - 交换两行(\ 1是第一个保存的部分, \ 2第二)。使用转义的文字换行符来实现可移植性

使用一些sed实现,您可以使用转义序列 \ n:\2\n\1代替。

答案 2 :(得分:5)

第一个问题:

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

下一个问题:按第二行排序

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

输出:

dobroye utro!
Good morning!
annyonghaseyo
hello
watashi
me

答案 3 :(得分:1)

假设输入文件如下:

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

您可以使用 Perl 进行交换和排序:

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

我得到的输出是:

% 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

如果您想在第一行(交换前)订购:

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

因此,如果原始文件如下所示:

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

输出应如下所示:

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

此版本应正确处理重复记录:

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

另一个版本,灵感来自Glenn发布的解决方案(包括记录交换并假设模式_ZZ_不在文本文件中):

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