2011-07-25 36 views
12

我一直在这样做,我不能再这样做了 - 我有数千行,我认为这是一个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 

回答

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

N - 输入的下一行追加到图案空间
\(.*\)\n\(.*\) - 之前保存模式空间 所述一个的所述匹配部分和换行之后的那个。
\2\\ \1 - 交换两行(\ 1是第一个保存的部分, \ 2第二个)。使用逃脱面值换行符便携

随着一些SED实现你可以使用转义序列 \ N:\2\n\1代替。

+0

谢谢 - 这个工作就像黄金!是否可以根据第一行的第一个字母按字母顺序重新排列?另外,看起来文件大小在这之后跳跃了大约30%,可能插入了一些符号?我没有看到任何空格等。我在vim中使用“:%s/\ s \ + $ //”删除所有尾随空白。编辑:如果有问题,我通过> output.txt保存了输出。 –

+0

@Google,你可以发布一个更大的你的输入样本和一个期望输出的例子(根据最后的订购要求)? –

+0

我更新了最初的问题 - 我希望它很清楚。如果不让我知道。 –

2

假设这样一个输入文件:

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 

而另一个版本,inspi红通过张贴格伦解决方案(记录交换包括假设模式_ZZ_没有出现在文本文件中):

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

哇,谢谢!它非常完美 - 我用bash脚本包装起来。你为我节省了很多工作。非常感谢! –

+0

经过仔细检查,似乎它的工作很好,但不处理重复。有没有什么办法可以妥善处理?它似乎会删除任何重复。 –

+0

@Google, 你是对的。增加了一个固定版本。 –

6

第一个问题:

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

下一个问题:由2号线

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

,其输出:

dobroye utro! 
Good morning! 
annyonghaseyo 
hello 
watashi 
me 
17

对于问题的第一部分,这里是交换具有SED彼此每隔一行而无需使用正则表达式的一种方法:

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

-n命令行抑制自动打印。命令h将当前行从模式空间复制到保留空间,n读入模式空间的下一行,并打印它p; g将第一行从保留空间复制回模式空间,将第一行复制回模式空间,然后p将其打印出来。

+1

这是非常好的! –

+0

真棒解决方案! – hovanessyan

+3

如果输入具有奇数行数,则不会输出最后一行数据。如果该行的输出需要:'sed的-n“$ P; H,N,P;克; p'' –