(一)闲聊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

command | awk '{print NR}' | tail -n1
command | awk 'END{print NR}'

2.grep + awk

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

3.sed

command | sed -n "$="

4.wc

command | wc –l

计算列数

1.思路将二维数组通过head -n1抽取成一维数组,通过${#val[@]}计算一维数组长度,从而获取列数

a=(`command | head -n1`) && echo ${#a[@]}

2.直接利用awk计算列数(要求command的输出中每一列都是有数据的,不能与awk的FS冲突,例如如果awk以空格为FS间隔符,则每一列的数据中不能有空格,否则容易出错)

command | head -n1 | awk -F ' ' '{print NF}'
command | awk -F ' ' '{print NF}' | head –n1

(三)应用举例:找出数组(矩阵)中缺值的列,或剔除缺值的列

例如有一个文件的内容如下

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--