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