对于文本的操作分为两种操作,一种是按行操作,一种是按列操作。
简单的命令有grep(行操作)和cut(列操作)。
复杂点的有sed(行操作)和awk(列操作)。
样例文本
hello tom
hi marry
how are you
什么是行操作:简单的例子就是,获取上面文本中带有hello的行就是行操作。
什么是列操作:简单的例子就是获取上面文本中的第一列操作。
package com.zzrenfeng.linux;
/**
* grep命令
*
* @author hanlipeng
*
*/
public class Grep {
/**
* [options]主要參数:
* -c:仅仅输出匹配行的计数。
* -I:不区分大 小写(仅仅适用于单字符)。
* -h:查询多文件时不显示文件名称。
* -l:查询多文件时仅仅输出包括匹配字符的文件名称。
* -n:显示匹配行及 行号。
* -s:不显示不存在或无匹配文本的错误信息。
* -v:显示不包括匹配文本的全部行。
*
* 命令正則表達式:
* . 匹配单个字符 如..X yiX能查出来
* ^ 匹配行首 ^d 每行第一个字符为d
* $ 匹配行尾 T$ 每行最后一个字符为T
* 匹配随意字符串
* \ 屏蔽特殊字符的含义
* A\{2\}B 字母A出现两次
* A\{2,\}B 至少出现两次
* A\{2,4\}B 出现2到4次
* [0-9]\{4\}xx[0-9]\{4\} 前四个是数字,中间是xx,后四个是数字
*
* 简单实用
* 过滤出行里面有hello的行
* grep 'hello' filename.txt
*
* 过滤出所有行里面不含hello的行
* grep -v 'hello' filename.txt
*
*/
}
package com.zzrenfeng.linux;
/**
* cut用法
* 命令可以从一个文本文件或者文本流中提取文本列。
*
* sort wc uniq
* @author rf
*
*/
public class Cut {
/**
* cut的用法:cut是对列进行截取的 相当于awk的用法
*
* 将 PATH 变量取出,我要找出第五个路径。
* echo $PATH | cut -d ':' -f 5
*
* 将 PATH 变量取出,我要找出第三和第五个路径。
* echo $PATH | cut -d ':' -f 3,5
*
* 将 PATH 变量取出,我要找出第三到最后一个路径。
* echo $PATH | cut -d ':' -f 3-
*
* 将 PATH 变量取出,我要找出第一到第三个路径。
* echo $PATH | cut -d ':' -f 1-3
*/
/**
* wc的命令
*
* wc主要是进行统计的
* wc -l /etc/passwd #统计行数,在对记录数时,很常用
* wc -w /etc/passwd #统计单词出现次
* wc -m /etc/passwd #统计文件的字符数
*/
/**
* sort [-fbMnrtuk] [file or stdin]
*
* 选项与参数:
* -f :忽略大小写的差异,例如 A 与 a 视为编码相同;
* -b :忽略最前面的空格符部分;
* -M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
* -n :使用『纯数字』进行排序(默认是以文字型态来排序的);
* -r :反向排序;
* -u :就是 uniq ,相同的数据中,仅出现一行代表;
* -t :分隔符,默认是用 [tab] 键来分隔;
* -k :以那个区间 (field) 来进行排序的意思
*
* sort 是默认以第一个数据来排序,而且默认是以字符串形式来排序,所以由字母 a 开始升序排序。
*
* 内容是以 : 来分隔的,我想以第三栏来排序,该如何
* cat /etc/passwd | sort -t ':' -k 3
*
* 默认是以字符串来排序的,如果想要使用数字排序:
* cat /etc/passwd | sort -t ':' -k 3n
*
* 默认是升序排序,如果要倒序排序,如下
* cat /etc/passwd | sort -t ':' -k 3nr
*
* 如果要对/etc/passwd,先以第六个域的第2个字符到第4个字符进行正向排序,再基于第一个域进行反向排序。
* cat /etc/passwd | sort -t':' -k 6.2,6.4 -k 1r
*
* 查看/etc/passwd有多少个shell:对/etc/passwd的第七个域进行排序,然后去重:
* cat /etc/passwd | sort -t':' -k 7 -u
*/
/**
* uniq [-icu]
*
* 选项与参数:
* -i :忽略大小写字符的不同;
* -c :进行计数
* -u :只显示唯一的行
*
* 注意:去重需要先排序,也就是只有两行是一块的才能去重
*/
}
package com.zzrenfeng.linux;
/**
* sed 是一种在线编辑器,它一次处理一行内容
*
* @author hanlipeng
*
*/
public class Sed {
/**
* sed用法
*
* 删除:d命令
* sed '2d' example-----删除example文件的第二行。
* sed '2,$d' example-----删除example文件的第二行到末尾所有行。
* sed '$d' example-----删除example文件的最后一行。
* sed '/test/'d example-----删除example文件所有包含test的行。
* sed -i '2d' example-----删除会被回写到文件,不加-i不会改变源文件
*
* 替换:s命令
* sed 's/test/mytest/g' example-----在整行范围内把test替换为mytest。如果没有g标记,则只有每行第一个匹配的test被替换成mytest。
* sed -n 's/^test/mytest/p' example-----(-n)选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的test被替换成mytest,就打印它。
* sed 's/^192.168.0.1/&localhost/' example-----&符号表示替换换字符串中被找到的部份。所有以192.168.0.1开头的行都会被替换成它自已加 localhost,变成192.168.0.1localhost。
* sed -n 's/\(love\)able/\1rs/p' example-----love被标记为1,所有loveable会被替换成lovers,而且替换的行会被打印出来。
* sed 's#10#100#g' example-----不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。
* 选定行的范围:逗号
*
*
* 多点编辑:e命令
* sed -e '1,5d' -e 's/test/check/' example-----(-e)选项允许在同一行里执行多条命令。如例子所示,第一条命令删除1至5行,第二条命令用check替换test。命令的执 行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。
*
* 从文件读入:r命令
* sed '/test/r file' example-----file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面。
*
* 写入文件:w命令
* sed -n '/test/w file' example-----在example中所有包含test的行都被写入file里。
*
* 追加命令:a命令
* sed '/^test/a\\--->this is a example' example '----->this is a example'被追加到以test开头的行后面,sed要求命令a后面有一个反斜杠。
*
* 插入:i命令
* sed '/test/i\\
*
*
* 后面的命令看help吧
*/
}
package com.zzrenfeng.linux;
/**
* awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
*
* @author hanlipeng
*
*/
public class Awk {
/**
* awk
*
* 如果只是显示最近登录的5个帐号
* last -n 5 | awk '{print $1}'
*
* 如果只是显示/etc/passwd的账户
* cat /etc/passwd |awk -F ':' '{print $1}'
*
* 如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以tab键分割
* cat /etc/passwd |awk -F ':' '{print $1"\t"$7}'
*
* 如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。
* cat /etc/passwd |awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "blue,/bin/nosh"}'
*
* 搜索/etc/passwd有root关键字的所有行
* awk -F: '/root/' /etc/passwd
*
* 搜索支持正则,例如找root开头的: awk -F: '/^root/' /etc/passwd
*
* 搜索/etc/passwd有root关键字的所有行,并显示对应的shell
* awk -F: '/root/{print $7}' /etc/passwd
*
* awk内置变量
* awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。
*
*
* ARGC 命令行参数个数
* ARGV 命令行参数排列
* ENVIRON 支持队列中系统环境变量的使用
* FILENAME awk浏览的文件名
* FNR 浏览文件的记录数
* FS 设置输入域分隔符,等价于命令行 -F选项
* NF 浏览记录的域的个数
* NR 已读的记录数
* OFS 输出域分隔符
* ORS 输出记录分隔符
* RS 控制记录分隔符
*
* 统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
*
* #awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
* filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
* filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
* filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
* filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh
*
*
* 使用printf替代print,可以让代码更加简洁,易读
* awk -F ':' '{printf("filename:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
*
*
*
* 高级awk编程
* 除了awk的内置变量,awk还可以自定义变量
*
* 下面统计/etc/passwd的账户人数
* awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
* root:x:0:0:root:/root:/bin/bash
* ......
* user count is 40
*
* 这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0:
* awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
* [start]user count is 0
* root:x:0:0:root:/root:/bin/bash
* ...
* [end]user count is 40
*
*
* 统计某个文件夹下的文件占用的字节数
* ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
* [end]size is 8657198
*
*
* 如果以M为单位显示:
* ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}'
* [end]size is 8.25889 M
* 注意,统计不包括文件夹的子目录。
*
*
*/
/**
* 条件语句以后需要了再进行学习
awk中的条件语句是从C语言中借鉴来的,见如下声明方式:
if (expression) {
statement;
statement;
... ...
}
if (expression) {
statement;
} else {
statement2;
}
if (expression) {
statement1;
} else if (expression1) {
statement2;
} else {
statement3;
}
统计某个文件夹下的文件占用的字节数,过滤4096大小的文件(一般都是文件夹):
ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
[end]size is 8.22339 M
循环语句
awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。
数组
因为awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key/value应用hash的表格里。由于hash不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,awk也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。
显示/etc/passwd的账户
awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
0 root
1 daemon
2 bin
3 sys
4 sync
5 games
......
这里使用for循环遍历数组
*/
}