awk

 理解awk的原理是必須的:讀入有'\n'換行符分割的一條記錄,將記錄按指定的域分隔符劃分域,$0表示所有域, $1表示第一個域, $n表示第n個域。 默認域分隔符是空格鍵或tab鍵。

 先來感受一下awk, 我們假設test.txt中的內容:


[plain] view plain copy

  1. xxx     Math English C++  Experiment  

  2. Monkey  100   90     95   Good  

  3. Cat     80    100    60   Perfect  

  4. Dog     90    60     70   Great  

  5. Tiger   95    85     90   Fantastic  

       之前, 我們用sed來輸出行, 現在, 我們來感受一下用awk輸出列, 如下:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print $2}' test.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  

       看到了吧, 這就是awk. 注意上面只能是單引號, 不能是雙引號, $2表示第二列。


      
       我們來看看awk的一般格式:awk [option]  'pattern {action}' test.txt,  比如上面的awk '{print $2}' test.txt, 此時,採用默認選項, 且條件永遠爲真。

       下面, 我們根據awk的原型來一一說明:

        

        A.awk 

        其實awk就相當於一個函數名, 沒什麼好說的了。


        B. option

        我們先看如下操作, 打印test.txt文件的第二列:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print $2}' test.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

        可以看到, 命令中沒有選項, 也就是採用了默認選項, 現在假設a.txt中的文件內容爲:



[plain] view plain copy

  1. xxx|Math|English|C++|Experiment  

  2. Monkey|100|90|95|Good  

  3. Cat|80|100|60|Perfect  

  4. Dog|90|60|70|Great  

  5. Tiger|95|85|90|Fantastic  

       我們再用awk '{print $2}' a.txt就不靈了, 爲什麼呢? 因爲awk '{print $2}' a.txt的選項爲空, 默認的是以空格爲分隔符, 顯然不能進行劃分。 那怎麼辦呢? 此時, 我們應該顯式地指明分隔符, 如下:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk -F "|" '{print $2}' a.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  

       這就對了。好了, 後續我們仍然針對test.txt, 不針對a.txt. 也就是說, 採用默認的選項。



       C. pattern

       這個最好理解了, 比如, 條件就是一種模式(但模式不僅僅是條件, 有可能是一些正則表達式等)。我們看到, 在awk '{print $2}' test.txt中, 是無條件的, 所謂無條件即爲真。 日本無條件投降, 大概就是這個意思。 當然, 爲了講清楚條件, 我們還是來看看:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '1<2 {print $2}' test.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $ awk '1<1 {print $2}' test.txt  

  11.   

  12. Administrator@51B6904C3C8A485 ~/learn_awk  

  13. $  

       我們看到, 當條件爲真的時候, 纔會有真正的打印, 反之, 打個屁。 如果要打印整個文件, 可以這麼搞:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '1' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Monkey  100   90     95   Good  

  5. Cat     80    100    60   Perfect  

  6. Dog     90    60     70   Great  

  7. Tiger   95    85     90   Fantastic  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $ awk '0' test.txt  

  11.   

  12. Administrator@51B6904C3C8A485 ~/learn_awk  

  13. $  


      可以看看到, 條件爲真, 有打印。 否則, 沒有打印。

       D. action

       這個好理解, 無非就是內置命令而已, 比如print $2, 如下:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print $2}' test.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  

       當然, 如果你喜歡C/C++語言格式, 那完全可以寫成:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{printf("%s\n", $2)}' test.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  


       實際上, 在pattern部分, 我們是可以用C/C++語言的if等關鍵字的, 如:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{if(1<2) printf("%s\n", $2)}' test.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $ awk '{if(1<1) printf("%s\n", $2)}' test.txt  

  11.   

  12. Administrator@51B6904C3C8A485 ~/learn_awk  

  13. $  




      我們看到, awk看似很小, 其實五臟俱全。 弄清了上面的基本構成, awk就算基本入門了。 既然已經與awk有了初步的戀愛感覺了, 那就要趁熱打鐵的練習一下。

      

      一. awk的內置變量

      1. $0表示整行, $n表示第n個分段, 如下:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print $0}' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Monkey  100   90     95   Good  

  5. Cat     80    100    60   Perfect  

  6. Dog     90    60     70   Great  

  7. Tiger   95    85     90   Fantastic  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $ awk '{print $2}' test.txt  

  11. Math  

  12. 100  

  13. 80  

  14. 90  

  15. 95  

  16.   

  17. Administrator@51B6904C3C8A485 ~/learn_awk  

  18. $  

      再如:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print $1, $3}' test.txt  

  3. xxx English  

  4. Monkey 90  

  5. Cat 100  

  6. Dog 60  

  7. Tiger 85  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  



      2. FILENAME表示文件名稱, 比如:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{printf("%s\n", FILENAME)}' test.txt  

  3. test.txt  

  4. test.txt  

  5. test.txt  

  6. test.txt  

  7. test.txt  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  

       可以看到, 文件名被打印出來了, 爲什麼是5個呢? 因爲awk是逐行處理的。



       3. NR是當前的行數, 可以理解爲number of row, 當然, 如果你非要說now row這樣的中式英語, 那也可以。總之, 你要明白, NR很有用。如下:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{printf("%d:%s\n", NR, FILENAME)}' test.txt  

  3. 1:test.txt  

  4. 2:test.txt  

  5. 3:test.txt  

  6. 4:test.txt  

  7. 5:test.txt  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  

       那要創建test1.txt---test5.txt怎麼搞呢? 也很簡單, 聯合我們之前介紹過的xargs, 如下:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{printf("%s%d\n", FILENAME, NR)}' test.txt | xargs touch  

  3.   

  4. Administrator@51B6904C3C8A485 ~/learn_awk  

  5. $ ls  

  6. test.txt  test.txt1  test.txt2  test.txt3  test.txt4  test.txt5  

  7.   

  8. Administrator@51B6904C3C8A485 ~/learn_awk  

  9. $  

    


      4. FNR是文件中的行數, 和NR還是有點小小區別的, 且看:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ cp test.txt test_bak.txt  

  3.   

  4. Administrator@51B6904C3C8A485 ~/learn_awk  

  5. $ awk '{printf("%d:%d:%s\n", NR, FNR, FILENAME)}' test.txt test_bak.txt  

  6. 1:1:test.txt  

  7. 2:2:test.txt  

  8. 3:3:test.txt  

  9. 4:4:test.txt  

  10. 5:5:test.txt  

  11. 6:1:test_bak.txt  

  12. 7:2:test_bak.txt  

  13. 8:3:test_bak.txt  

  14. 9:4:test_bak.txt  

  15. 10:5:test_bak.txt  

  16.   

  17. Administrator@51B6904C3C8A485 ~/learn_awk  

  18. $  

     


     5. NF表示當前行有多少個段, 學這些東西的時候, 不要死記, 要知道NF是number of field的縮寫, 那就清晰了, 如下:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ echo "good good study" | awk '{print NF}'  

  3. 3  

  4.   

  5. Administrator@51B6904C3C8A485 ~/learn_awk  

  6. $  

      可見有3個段, 下面我們看看test.txt的每行是不是有5個段:

[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print NF}' test.txt  

  3. 5  

  4. 5  

  5. 5  

  6. 5  

  7. 5  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  

      果然如此。


      6. FS是filed seperator, 也就是段分割符號, 默認情況下爲空格, 下面我們不用默認的, 而用"|", 如下:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk -F "|" '{print FS}' test.txt  

  3. |  

  4. |  

  5. |  

  6. |  

  7. |  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  

      


      當然, 還有其他的一些內置變量, 在此就不一一舉例了, 以後要用的時候, 一查便知。


      二. 常見的一些pattern

       1. 條件式的pattern, 我們其實已經熟悉了, 比如:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '1' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Monkey  100   90     95   Good  

  5. Cat     80    100    60   Perfect  

  6. Dog     90    60     70   Great  

  7. Tiger   95    85     90   Fantastic  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $ awk '1<=1' test.txt  

  11. xxx     Math English C++  Experiment  

  12. Monkey  100   90     95   Good  

  13. Cat     80    100    60   Perfect  

  14. Dog     90    60     70   Great  

  15. Tiger   95    85     90   Fantastic  

  16.   

  17. Administrator@51B6904C3C8A485 ~/learn_awk  

  18. $ awk '1<=0' test.txt  

  19.   

  20. Administrator@51B6904C3C8A485 ~/learn_awk  

  21. $  

       


       2. 來個複雜一點的條件pattern, 如下:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk 'length > 30' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Cat     80    100    60   Perfect  

  5. Dog     90    60     70   Great  

  6. Tiger   95    85     90   Fantastic  

  7.   

  8. Administrator@51B6904C3C8A485 ~/learn_awk  

  9. $  


        3. 繼續條件pattern, 如下:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '$1=="Cat"' test.txt  

  3. Cat     80    100    60   Perfect  

  4.   

  5. Administrator@51B6904C3C8A485 ~/learn_awk  

  6. $  

        繼續加個條件:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '$1!="Cat" && $3>=85' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Monkey  100   90     95   Good  

  5. Tiger   95    85     90   Fantastic  

  6.   

  7. Administrator@51B6904C3C8A485 ~/learn_awk  

  8. $  

      


       4. 打印第2-4行:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk 'NR>=2 && NR<=4 {print $0}' test.txt  

  3. Monkey  100   90     95   Good  

  4. Cat     80    100    60   Perfect  

  5. Dog     90    60     70   Great  

  6.   

  7. Administrator@51B6904C3C8A485 ~/learn_awk  

  8. $  

       別忘了, 我們的sed也可以, 也蠻牛逼的:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ sed -n "2,4"p test.txt  

  3. Monkey  100   90     95   Good  

  4. Cat     80    100    60   Perfect  

  5. Dog     90    60     70   Great  

  6.   

  7. Administrator@51B6904C3C8A485 ~/learn_awk  

  8. $  

       好了, 條件式的pattern我們介紹到這裏, 下面我們介紹與正則表達式有關的一些pattern.



       5. 行過濾, 類似於grep的功能, 如:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '/Cat/' test.txt  

  3. Cat     80    100    60   Perfect  

  4.   

  5. Administrator@51B6904C3C8A485 ~/learn_awk  

  6. $  

       對了,sed也有類似功能, 如下:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ sed -n "/Cat/"p test.txt  

  3. Cat     80    100    60   Perfect  

  4.   

  5. Administrator@51B6904C3C8A485 ~/learn_awk  

  6. $  


    

      6. 那能不能實現grep -v的功能呢? 肯定可以, 如果你認爲不能, 那太小看awk了, 且看:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '!/Cat/' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Monkey  100   90     95   Good  

  5. Dog     90    60     70   Great  

  6. Tiger   95    85     90   Fantastic  

  7.   

  8. Administrator@51B6904C3C8A485 ~/learn_awk  

  9. $  



      7. 輸出以xxxxxx開頭的行:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '/^C/' test.txt  

  3. Cat     80    100    60   Perfect  

  4.   

  5. Administrator@51B6904C3C8A485 ~/learn_awk  

  6. $ awk '/^(C|D)/' test.txt  

  7. Cat     80    100    60   Perfect  

  8. Dog     90    60     70   Great  

  9.   

  10. Administrator@51B6904C3C8A485 ~/learn_awk  

  11. $  

  
      8. 輸出以xxxxxx結尾的行:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '/t$/' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Cat     80    100    60   Perfect  

  5. Dog     90    60     70   Great  

  6.   

  7. Administrator@51B6904C3C8A485 ~/learn_awk  

  8. $  

       


      9. 自然而言地, 在一個pattern裏, 我們可以既有正則又有條件, 如:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '/100/ && $4 >= 60' test.txt  

  3. Monkey  100   90     95   Good  

  4. Cat     80    100    60   Perfect  

  5.   

  6. Administrator@51B6904C3C8A485 ~/learn_awk  

  7. $ awk '/100/ && $4 > 60' test.txt  

  8. Monkey  100   90     95   Good  

  9.   

  10. Administrator@51B6904C3C8A485 ~/learn_awk  

  11. $  


      10. 最後再來一個:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '/^x/, /^D/' test.txt  

  3. xxx     Math English C++  Experiment  

  4. Monkey  100   90     95   Good  

  5. Cat     80    100    60   Perfect  

  6. Dog     90    60     70   Great  

  7.   

  8. Administrator@51B6904C3C8A485 ~/learn_awk  

  9. $  

       當然了, sed肯定也有此功能, 不信你就翻翻我之前的博文。



       三. 常見的一些action, 實際上主要是內置函數

       1. 最常見的print, printf, 如下:


[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print $2}' test.txt  

  3. Math  

  4. 100  

  5. 80  

  6. 90  

  7. 95  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $ awk '{printf("%d\n", $2)}' test.txt  

  11. 0  

  12. 100  

  13. 80  

  14. 90  

  15. 95  

  16.   

  17. Administrator@51B6904C3C8A485 ~/learn_awk  

  18. $  


       2.  在action中也可以有種邏輯, 比如打印第2-4行:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{if(NR>=2 && NR<=4) print $0}' test.txt  

  3. Monkey  100   90     95   Good  

  4. Cat     80    100    60   Perfect  

  5. Dog     90    60     70   Great  

  6.   

  7. Administrator@51B6904C3C8A485 ~/learn_awk  

  8. $  

       當然, 你也可以把這個if條件移動到pattern中去, 如:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk 'NR>=2 && NR<=4 {print $0}' test.txt  

  3. Monkey  100   90     95   Good  

  4. Cat     80    100    60   Perfect  

  5. Dog     90    60     70   Great  

  6.   

  7. Administrator@51B6904C3C8A485 ~/learn_awk  

  8. $  


      3.  計算字符串長度, 相當於C/C++中的length函數

[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ echo "good good study" | awk '{print length}'  

  3. 15  

  4.   

  5. Administrator@51B6904C3C8A485 ~/learn_awk  

  6. $  

       再如:



[plain] view plain copy

  1. Administrator@51B6904C3C8A485 ~/learn_awk  

  2. $ awk '{print length}' test.txt  

  3. 36  

  4. 30  

  5. 33  

  6. 31  

  7. 35  

  8.   

  9. Administrator@51B6904C3C8A485 ~/learn_awk  

  10. $  


      


來源: http://blog.csdn.net/stpeace/article/details/46848873


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章