awk與sed:一個關於多行處理的例子


  前幾天在CSDN上看到一個帖子 http://bbs.csdn.net/topics/390848841 ,樓主貼了下面的問題:
   
   
   
           
  1. 例:
  2. 12345
  3. 67890
  4. 1234567890
  5. 123
  6. 4567890
  7. 如何能把上面數據轉換成
  8. 1234567890
  9. 1234567890
  10. 1234567890
    看了幾位網友的回復,覺得還是挺有意思,也收獲了一些知識,因為部分網友只給出了解決方法,沒有解釋下,我根據自己的理解,對幾個答案解釋下(不一定准確,錯誤之處請指正)
我認為錯的答案
1    首先樓主給出了一個他說調試不出來的答案:
   
   
   
           
  1. sed 's/(?!90)\n//g'
?!應該是非pattern結尾的意思,這個答案應該是說把非90結尾的行的換行符換位空。
這個答案應該是不可行的。sed默認單行模式,一次處理一行,運行時發現,就算我們把換行符去掉了,sed命令結束后,還是將它當成完整的一行輸出(也就是說,應該是自動又加上換行符了)
2.    有一位網友,覺得其他答案太復雜,給出了下面的方法
sed ‘N;s/\n//g’

         這個答案使用了sed的多行模式,但應該是無法實現樓主的目的的。我們看運行結果“
windeal@ubuntu:~/Windeal/shell$ sed 'N;s/\n//g' a.txt 
1234567890
1234567890123
4567890

可以看出,sed 的N命令把第二行接到第一行后面,把第四行接到第三行后面,沒有考慮到我們目標中:只有非90結尾的才把下一行附加上來。所以第四行的123被附加到第三行1234567890而出現了錯誤的結果。

我認為對的答案
再來看兩個我認為對的答案:
1.
sed -e '/^/{:loop /90$/!{N;b loop};s/\n//g}' test.txt > t2.txt
改一下好理解一點就是
sed '{:myloop /90$/!{N;b myloop};s/\n//g}' a.txt

/^/的意思我沒弄明白,應該是匹配每一行吧
      在該命令中,myloop是一個自定義的標簽。類似程序語言中goto用的標簽。 N表示多行模式,b表示分支(相當於goto)
這樣就好理解了,sed會讀取一行內容,如果這一行不是以90結尾,/90$/! 就為真,進入 {N;b myloop}。N就進入了多行模式,把下一行附加上來,然后進入分支b myloop,在判斷是不是以90結尾,這樣反復讀取,直到讀到以90結尾的行。接下來模式空間的讀取工作已經完成,進入下一個命令,替換, s/\n//g​這個命令把當前模式空間的換行符都轉換為空,也就是拼接成一行。
    如此,我們就完成了我們要的目的。

2. 
awk '{if($0~/90$/){print}else{printf("%s",$0)}}' a.txt 
這個答案讀取了一行的所以字段(實際上就1個字段,) 用$0表示,然后 if($0~/90$/)判斷是不是以90結尾。
如果以90結尾,就輸出當前行數據。
如果不是,就格式化輸入當前航的字符串
注意print和printf的區別





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM