2013-05-03 99 views
0

這裏是我的示例清單:如果腳本正在逐行處理,如何返回以處理前一行?

AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III1   <----- I want to remove this 
GGG HHH III3 >>updated <----- I want to keep this 
JJJ KKK LLL7 

,因爲我遍歷使用for循環,我想利用具有「>>更新」中,並返回一個行的每一行的筆記列表並刪除舊行(未更新),然後向前移動到「>>更新」行之後的下一行。所以基本上我的最終輸出將是:

AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 

我使用awk來解析從shell腳本其他字段的值,但我只是不太清楚如何做到這一點向後和向前的一步。任何幫助將不勝感激。

+1

向我們展示迄今爲止已編碼的awk,這將是一個很好的開始來幫助你。 – fedorqui 2013-05-03 09:57:10

+0

真正的名單有多大?如果它不是太大,那麼一個可能的解決方案是將整個批量讀入一個數組中。隨機訪問很容易。 – cdarke 2013-05-03 10:01:13

+1

那麼實際的專欄是很醜陋的。他們不完全排隊,有些領域是空的,我也必須從列A到列E等替換一些領域... – fembot 2013-05-03 10:07:58

回答

5
awk '{a=$0;getline; if ($0~/>>updated/)print $1,$2,$3; else print a,"\n"$0}' file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 
+0

再次@sudo_O所以我實際上正在閱讀一個文件,做一個'對於我在'cat myfile'循環中依次讀取它,並使用awk解析每行中的每個字段並將輸出寫入臨時文件。根據上面的建議,我是否應該通過一遍並將所有內容寫入文件,然後使用tac cmd再次進行檢查? – fembot 2013-05-03 10:02:24

+1

呃,循環訪問文件的正確方法是'while read i;做...完成 tripleee 2013-05-03 10:10:27

+0

@tripleee我也可以做到這一點:)但仍然不能解決我的問題,當我到達有匹配「>>更新」字段的行時,我該如何返回一行,用新行替換舊行的內容。 – fembot 2013-05-03 10:13:27

4

這可能爲你工作(GNU SED):

sed -r '$!N;s/.*\n(.*)\s+>>updated\s*$/\1/;P;D' file 

請模式空間兩條直線和刪除當最後的比賽,你的要求第一。

一個AWK解決方案可能是:

awk 'sub(/ *>>updated.*/,""){l=$0;next};NR>1{print l};{l=$0};END{print l}' file 
+0

我對sed有點粗糙。我知道如何進行替換,但目前爲止我只用一行代碼完成替換。如何在模式空間中保留兩行? – fembot 2013-05-03 10:17:02

+1

@fembot sed命令'N'將下一行讀入模式空間,並用換行符'\ n'將它與當前行分開。命令'$!N'表示除了最後一行總是在下一行讀取。與'P'和'D'結合使用,可以打印/刪除第一個換行符,這些命令允許sed在流過文件時處理2行窗口。 – potong 2013-05-03 10:35:59

+0

謝謝,我現在要去玩這個遊戲。 – fembot 2013-05-03 10:37:10

3

tac是好的,但不是默認爲所有發行。如果你沒有它用,這裏是一個awk單個進程的一行:

awk -F' >>' 'p{if($2~/updated/){p=$1;next}print p}{p=$0}END{print p}' file 
+0

我錯誤地回答了我的初始查詢。如果我的當前行是「>>更新」,我想刪除它之前的行,並將其替換爲「>>更新」行中的值。 – fembot 2013-05-03 11:18:39

+0

@fembot我的腳本完成你所說的內容,輸出與你的問題完全一樣。 – Kent 2013-05-03 11:31:00

+0

+1如果記憶是一個重大問題,則採用正確的方法。 – 2013-05-03 12:22:49

1
perl -lne 'if(/\>\>updated/){pop @a;s/\>\>updated//g;push @a,$_}else{push @a,$_}END{print join "\n",@a}' your_file 

測試:

> cat temp 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III1 
GGG HHH III3 >>updated 
JJJ KKK LLL7 
> perl -lne 'if(/\>\>updated/){pop @a;s/\>\>updated//g;push @a,$_}else{push @a,$_}END{print join "\n",@a}' temp 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 
> 
+0

謝謝!這也工作! – fembot 2013-05-04 11:38:07

1

最簡單的方法是建立的一個數組在你的輸入文件中只有一行,但只有當>>更新不存在時纔會增加數組索引,這樣包含更新的行將覆蓋數組中的前一個條目,然後在到達文件結尾時僅打印數組的內容:

$ cat file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III1   <----- I want to remove this 
GGG HHH III3 >>updated <----- I want to keep this 
JJJ KKK LLL7 

$ awk '!/>>updated/{++numLines} {line[numLines]=$0} END {for (nr=1;nr<=numLines;nr++) print line[nr]}' file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 >>updated <----- I want to keep this 
JJJ KKK LLL7 

如果你想擺脫在該行的更新>>和隨後的文字,你可以爲它的存在改變測試的測試,試圖將其刪除:

$ awk '!sub(/ *>>updated.*/,""){++numLines} {line[numLines]=$0} END{for (nr=1;nr<=numLines;nr++) print line[nr]}' file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 

如果>>更新是存在的然後sub()將它刪除並返回成功,所以你知道>>更新是存在的,否則sub()將什麼也不做,但返回失敗,所以你知道>>更新是缺席。

相關問題