天天看點

Shell或指令行計算數組或檔案的行數和列數

(一)閑聊Linux Shell 程式設計

都說中國文化博大精深(例如漢字),但作為作業系統中的佼佼者,Linux雖然時間并不長,但同樣也是博大精深。誰也不敢說自己已經熟練的掌握了Linux中所有的内容,除了知識點衆多以外,快速的發展和更新使得Linux越來越強大,也使得Linux在短時間内越來越難掌握。是以說,知識真是一個積累的過程,但有時候腦袋還真記不住,比如Linux Bash裡面的變量替換、Bash變量展開等,如果感覺自己進展不順利就趕緊用筆記吧。

學過Java、php、python、shell等再回來學C,發現C真的是很難。難點在哪?感覺拿到C以後真的無從下手,作為Java來說,極好的IDE、完善的文檔和衆多的學習人數使得擷取Java幫助并不難。對于php、python、shell等腳本語言來說,豐富的函數庫介紹和幫助系統對于英語熟練的人來說非常簡單。而作為C這一古老的語言,要想檢視它的函數庫和幫助系統,可能是自己還沒有真正的認識C,正因如此我頗感到有心無力。

回過頭來再說Shell,Bash Shell在Linux系統管理和維護中往往發揮出巨大的作用,系統管理、自動化、監控報警、計劃任務等樣樣精通。幾乎在Linux下能想到的功能,甚至系統函數中的功能,都有Linux指令與之對應,Linux指令的強大使得Shell也變得強大。Shell本身也是程式,有人說程式=算法+資料結構,但對于Shell而言,程式=算法+指令,因為Shell 是解釋型語言,它的變量都是弱類型(Java、C等都是強制類型),由此可知指令對于Shell來說多麼重要。

但當你想用Shell處理一些它不擅長的操作時,你就會覺得這挺痛苦,盡管這個想法本身也是痛苦的,畢竟Shell也不是萬能的。比如你想用Bash Shell實作二維數組,還想有若幹的指令或函數去處理二維數組,那真是很不容易,盡管你可以将二維數組看作是特殊的一維數組。

Linux像UNIX一樣,程式間的标準接口都是文本(即所謂的文本流),Linux用文本流傳遞資料,最能展現文本流的就是管道。如果你觀察仔細,Linux中的許多指令的輸出都是看起來以某種格式格式化了的。看起來像數組,像矩陣,這就是為什麼我想把數組放到題目中去。由于文本流的存在,指令的輸出可以變成普通檔案,它看起來就像一個數組,特别像一個二維數組。如何操作這些輸出其實也可以看成操作一個二維數組。

Shell程式設計的核心,除了需要對大量指令的熟練掌握和設計合适的算法(包括程式結構)外,對于資料的處理越來越重要,對于别的程式而言同樣也是對資料(資料庫)的增删改查。我觀察到幾乎所有的資料處理都是按照行和列的形式處理的,列印/替換/删除/增加多少行多少列的内容,想想sed、awk這些程式想必很容易聯想的到。

(二)Shell或指令行計算數組或檔案的行數和列數

也許計算行數對于Linux世界是最重要的,有很多種方法。

1.awk + tail

1

2

<code>command</code> <code>| </code><code>awk</code> <code>'{print NR}'</code> <code>| </code><code>tail</code> <code>-n1</code>

<code>command</code> <code>| </code><code>awk</code> <code>'END{print NR}'</code>

2.grep + awk

<code>command</code> <code>| </code><code>grep</code> <code>-n </code><code>""</code> <code>| </code><code>awk</code> <code>-F </code><code>":"</code> <code>'{print $1}'</code> <code>| </code><code>tail</code> <code>–n1</code>

3.sed

<code>command</code> <code>| </code><code>sed</code> <code>-n </code><code>"$="</code>

4.wc

<code>command</code> <code>| </code><code>wc</code> <code>–l</code>

計算列數

1.思路将二維數組通過head -n1抽取成一維數組,通過${#val[@]}計算一維數組長度,進而擷取列數

<code>a=(`</code><code>command</code> <code>| </code><code>head</code> <code>-n1`) &amp;&amp; </code><code>echo</code> <code>${</code><code>#a[@]}</code>

2.直接利用awk計算列數(要求command的輸出中每一列都是有資料的,不能與awk的FS沖突,例如如果awk以空格為FS間隔符,則每一列的資料中不能有空格,否則容易出錯)

<code>command</code> <code>| </code><code>head</code> <code>-n1 | </code><code>awk</code> <code>-F </code><code>' '</code> <code>'{print NF}'</code>

<code>command</code> <code>| </code><code>awk</code> <code>-F </code><code>' '</code> <code>'{print NF}'</code> <code>| </code><code>head</code> <code>–n1</code>

(三)應用舉例:找出數組(矩陣)中缺值的列,或剔除缺值的列

例如有一個檔案的内容如下

1 1 2 3   

1   3 5    

2 3 4    

1 2 3 4

通過Shell腳本将其變為

1 2   

1 3    

2 4    

1 3

思路:

(1)分析每一列的行數,如果列的行數小于最大行數,則該列無效,将其剔除。

(2)考慮到有可能某一列全為空,例如這一列沒有資料,并與awk用的FS值相同,則考慮将相鄰兩列相同的合并為一列。例如有一個檔案的内容如下:

1 1 2 3   3   

1   3 5   4    

2 3 4     7    

1 2 3 4   7    

5   5     8     

1 3 4 5   5

将空格換成a:

1a1a2a3aaa3   

1aaa3a5aaa4    

2a3a4aaaaa7    

1a2a3a4aaa7    

5aaa5aaaaa8    

1a3a4a5aaa5

就應該把8、9、10列合并成一列,變為:

1a1a2a3a3   

1aaa3a5a4    

2a3a4aaa7    

1a2a3a4a7    

5aaa5aaa8    

1a3a4a5a5

再變為:

1 1 2 3 3   

1   3 5 4    

2 3 4   7    

1 2 3 4 7    

5   5   8    

1 3 4 5 5

此時再經過處理以後就會變為

1 2 3   

1 3 4    

2 4 7    

1 3 7    

5 5 8    

1 4 5

--end--