2011-07-25 35 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'' –