shell_processing
1、文本处理_2:grep,sed,awk
2、regular_expression
3、Test
一、文本处理_2
1、grep --Linux处理正则表达式的主要程序。正则表达式是一种符号表示法,用于识别文本模式
常用选项:
-w --匹配单词的边界
-o --输出匹配的那部分,而不是整行
-i --忽略大小写
-R --递归,用于搜索目录下的文件
-l --输出符合条件的文件名
-n --显示匹配记录的行号
-v --显示不符合条件的结果
-c --输出匹配的记录的总数
-A --输出下文(after)
-B --输出上文(before)
-C --输出上下文(context)
-q --不输出结果,常用于条件测试
-E --使用扩展的正则表达式;表达重复的数量时,在大括号前面不需要反斜杠,这样正则表达式就很简洁,易读
# grep bin /etc/passwd --把/etc/passwd 中包含 bin 的行列出来
# grep -w bin /etc/passwd --对搜索字符有边界限制
# grep -o bin /etc/passwd --只列出匹配到的字符串
# grep -oi nobody /etc/passwd --将匹配到的字符列出,不区分大小写
# grep -Rl AUTOSWAP /etc/sysconfig/ --指定目录里面,哪个文件包含了字符串AUTOSWAP
# grep -n bash /etc/passwd | awk -F: '{print $1}' --找出指定文件中 bash 所在的行的行号
# grep -n bin /etc/passwd | wc -l --找出指定文件中有多少行包含了单词bin
# grep -nv bash /etc/passwd --找出 /etc/passwd 中不包含bash 的行
# grep -c root /etc/passwd --输出匹配行的总数
# grep -A2 mail /etc/passwd --打印出指定文件中包含 mail 的行,同时打出其下面2行
# grep -B2 mail /etc/passwd --同上,同时打出其上面2行
# grep -C2 mail /etc/passwd --同上,同时打出其上下面各2行
# grep -q root /etc/passwd --不输出结果,经常用于脚本中,用来做测试
# echo $? --返回值为 0,匹配到字符;否则未匹配到指定字符
# ls /bin | grep '^.\{5\}$' --输出 /bin 目录下只有五个字符的命令
# ls /bin | grep -E '^.{5}$' -- 使用扩展的正则表达式
# grep -Eo '/[^:]*nologin$' /etc/passwd --正则表达式与边界限制组合
# echo -e "1\n2" -- -e,使 echo 使用正则表达式
--------------------------------------------------------------------------------------------------------------
# cat lines | grep -v '^$' |grep -vE '^\s+$' --删除含有空格与含有TAB的空白行
2、sed --流编辑器,常常用于脚本中
范围指定:不明确指定的话,默认是所有的行;可以是行号;或者正则表达式
动作指定:
d --删除
s --替换
n --关闭默认的输出
p --打印
e --连续符
-i --将修改结果写入原文件,默认是将修改结果输出到标准输出
i --在前面插入
a --在后面插入
-r --使用扩展的正则表达式,使用这个参数后正则表达式的表示方法会更加方便。相当于 grep 里的 -E
2.1、删除
# cat /etc/passwd | sed '3d' --删除第 3 行
# cat /etc/passwd | sed '3,$d' --删除第 3 行至最后
# cat /etc/passwd | sed '10,20d' --删除第 10 行至第 20 行
# head /etc/passwd | cat -n |sed -e 1d -e 3d --删除第 1 行与第 3 行
2.2、替换
# echo hello | sed 's/l/L/' --把小写 l 替换成大写 L,只匹配第 1 个 l
# echo hello | sed 's/l/L/g' --匹配所有的 l
# grep root /etc/passwd | sed 's/root/ROOT/' --为指定范围,替换所有行第 1 个 root
# grep root /etc/passwd | sed '1s/root/ROOT/' --只替换第 1 行第 1 个 root
# echo "hello world" | sed 's/world//' --将字符串替换为空
替换动作的范围:
s/a/A/ --替换每行第一个a
s/a/A/g --替换每行所有a
s/a/A/3 --替换每行第3个a
s/a/A/3g --替换每第3个至最后一个a
替换命令的分割符:
分隔符斜杠/ 可以换成任何其它的字符,需要注意的是,如果需要处理的数据中包含了分隔符,就必须对该字符进行转义,举例如下:
# echo /etc/passwd | sed 's/\//_/g' --将字符串中的斜杠替换成下划线
# echo /etc/passwd | sed 's#/#_#g' --作用同上,使用其他字符作为分隔符
2.3、输出指定行
# sed -n '1,5p' /etc/passwd -- -n关闭了默认的输出,然后只输出第1至第5行
# sed -n '/root/p' /etc/passwd -- 输出包含指定关键字的行
2.4、插入
# cat /etc/passwd | sed '5i good morning' --在第 5 行前面插入一行
# cat /etc/passwd | sed '3a good morning' --在第 3 行后面插入一行
# cat /etc/passwd | sed '4i good morning' | sed '3a good morning' --通过管道可随意插入
# cat /etc/passwd | sed -e '4i good morning' -e '3a good morning' --也可使用连续符
2.5、正则
# sed '/^.\{5\}x/d' /etc/passwd | cat -n --删除指定文件第 6 个字符为 x 的每行
# sed -r '/^.{5}x/d' /etc/passwd --同上
# echo 123456789ABCDEF | sed -r 's/^(.{2})...(.*)$/\1\2/' --删除第 3 至第 5 的字符
# echo 123456789ABCDEF | sed -r 's/^(.{2}).(.*)$/\1\2/' --删除第 3 个字符
# echo 123456789ABCDEF | sed -r 's/^(.{2}).{10}(.*)$/\1\2/' --删除从3个字符开始的10个字符
# echo abc | sed -r 's/[a-z]/\u&/g' --小写转为大写
# echo ABC | sed -r 's/[A-Z]/\L&/g' --大写转为小写
# echo ABC | sed -r 's/./\l&/g' --同上
# sed -r -e '/^$/d' -e '/^\s+$/d' /path/file --删除空白行 以及 含有空格的空白行
# sed -r '/^(\s+)?$/d' /path/file --同上
# sed -r '/xxxxxx/d' --删除包含指定关键字的行
3、awk --文本分析工具
-F --字段分割符,可以是一个字符,也可以是多个字符。默认的分割符为单个或连续的空格
$NF --最后一个列,NF 是number of fields:有字段的总数
$0 --整条记录
# awk -F '[ :]' '{print $3,$4}' /etc/passwd --以 【空格符】 or 【:】 为分隔符
# head /etc/passwd | awk -F: '{print $1,$2}' | column -t
# echo 'hello world, good morning' | awk -F, '{print $1}'
# head -n5 /etc/passwd | awk -F: '{print $NF}' --拿文件各行的最后一列,不管文件几行内容列数是否相同
3.1、FS
Field separator:字段分割符。字段分割符除了可以通过命令行选项 -F 来指定外,还可以在awk 里面指定
BEGIN:后面的代码会在处理第一行数据之前先执行,可以在这里做一些前期的设定,比如设定分割符FS
# head -n5 /etc/passwd | awk 'BEGIN{FS=":"} {print $1}'
# head -n5 /etc/passwd | awk -F: '{print $1}'
3.2、NR
number of records:到当前行为止,总共处理的行数
# head /etc/passwd | awk '{printf("%05d:: george--%s\n",NR,$0)}' --NR统计总共处理的行数,通过%05d的格式输出
# awk 'END{print NR}' /etc/passwd --直接用来计算总行数
# awk -F: '{if (NR==1){print $1}}' /etc/passwd --只处理第一行
# awk -F ":" 'NR==2{print $1}' /etc/passwd --输出文件第2行的第一列
# awk -F ":" "NR==2{print \$1}" /etc/passwd --输出文件第2行的第一列
3.3、FNR
# ls -l /etc/ | sed 1d | awk 'BEGIN{print "start to process "} {total = total + $5} END{print NR " line Finished,resrlt: " total " kb"}' --初略计算 /etc 下的文件大小
3.4、结合正则
# ls -l | sed 1d | awk '{print $5,$0}' | sort -k1,1h | sed -r 's/^[^ ]+\s*//' --将当前目录的文件按文件大小排列。[^ ]+表示多个非空,\s 表示空格符
3.5、实例
# awk '{print $1}' access.log |sort|uniq -c|sort -nr|head -10 --分析access.log获得访问前10位的ip地址
二、regular_expression
1、正则表达式
正则表达式是对字符串操作的一种逻辑公式;就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,
这个“规则字符串”用来表达对字符串的一种过滤逻辑;规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普
通字符一起表示一个模式,这就是正则表达式(Regular Expression)
2、特点
2.1、灵活性、逻辑性和功能性非常的强;
2.2、可以迅速地用极简单的方式达到字符串的复杂控制。
2.3、对于刚接触的人来说,比较晦涩难懂
3、单字符表示法
. --匹配任意字符
\d --匹配一个数字字符。等价于 [0-9]
\D --匹配一个非数字字符。等价于 [^0-9]
\f --匹配一个换页符。等价于 \x0c 和 \cL
\n --匹配一个换行符。等价于 \x0a 和 \cJ
\r --匹配一个回车符。等价于 \x0d 和 \cM
\s --匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]
\S --匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
\t --匹配一个制表符。等价于 \x09 和 \cI
\v --匹配一个垂直制表符。等价于 \x0b 和 \cK
\w --匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'
4、边界表示法
^ --字符串的开头
$ --字符串的结尾
\b --单词边界
\B --非单词边界
\< --单词左边界
\> --单词右边界
5、分组表示法
(abc) --一组连续的字符abc
(aa|bb) --一组连续的字符ab 或者 bb
6、字符集合
[xyz] --字符集合。匹配所包含的任意一个字符
[^xyz] --负值字符集合。匹配未包含的任意字符
[a-z] --字符范围。匹配指定范围内的任意字符
[^a-z] --负值字符范围。匹配任何不在指定范围内的任意字符
7、数量表示法
--用来表示前面的一个字符,或者一组字符重复的次数
* --任意次, c >= 0
+ --至少1次, c >= 1
? --0次或者1次, c == 0 || c == 1
{m} --m 次, c == m
{m,} --至少m 次, c >= m
{m,n} --m次 至 n次, c >= m && c <= n
注意:默认情况下,数量表示符只作用于前面一个字符,若需要作用于前面多个字符,可以使用(...)把前面需要匹配的多个字符括起来
8、特殊字符表示法
^ $ . * + ? | \ { } [ ] ( ) 都有特殊意义的,如果需要表示这些符号,则可以用反斜杠对它们进行转义
9、引用表示法
从左边开始数左边小括号,数字从1开始,被第一对括号匹配的字符可以用\1 来引用,第二对可以用\2 来引用,以此类推
# echo abcabcabcaabb | grep -E '(a(bc)){2}\1' --color
# echo abcabcabcaabb | grep -E '(a(bc)){2}a\2' --color
# echo "hello world, hello world, hello beautiful world" | grep -E --color '((hello) (world)), \1, \2 .* \3'
10、其他表示方法
# date
# date | grep --color -oE '([0-1][0-9]|2[0-3])(:[0-5][0-9]){2}' --时间表示
# echo 2014-07-07 12:30:30 | grep --color -E '[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])' --日期表示
# ifconfig | grep --color -E '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' --IP地址表示
# ifconfig | grep --color -E '([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}' --MAC表示
三、测试
1、获取eth0的IP地址
# ifconfig eth0 | grep 'inet addr' | awk -F: '{print $2}' | awk '{print $1}'
# ifconfig eth0 | grep 'inet addr' | sed 's/.*addr://;s/ .*//'
2、查看root 用户的登录shell
# grep ^root /etc/passwd | awk -F: '{print $NF}'
3、查看/etc/passwd中有多少种登录shell
# awk -F: '{print $NF}' /etc/passwd | sort -u | wc -l
# sed 's/.*://' /etc/passwd | sort -u | wc -l
4、计算多个文件的总行数/总大小
# cat * | wc -l
# cat * | wc -c
5、计算字符串的长度
# echo 123 | wc -c -- 多出的一个是换行符
# echo -n 123 | wc -c -- 禁止输出换行符
6、在文件第一行之前和最后一行之后输出一些字符
# cat /etc/hosts | sed -e '1i ***********************' -e '$a ***********************'
# cat /etc/hosts | awk 'BEGIN{print "xxxxxxx"} {print $0} END{print "xxxxxxx"}'
7、输出系统开放的所有端口号
# netstat -tulpn | awk '{print $4}' | awk -F: '{print $NF}' | grep [0-9] | sort -nu
8、计算在线用户
# who | wc -l
9、历史开关机记录
# last -x | grep -E 'reboot|shutdown'
10、查根文件系统的可用空间
# df -h | grep " /$" | awk '{print $(NF-2)}'
11、查看sshd 登录记录,输出时间,用户名,客户端IP
# grep -E 'sshd.*Accepted pub' /var/log/secure-20170528 | awk '{print $1,$2,$3,$9,$11}'
12、系统至开机总运行时间
# uptime | awk -F, '{print $1,$2}' | sed 's/.*up //' | tr -s " "
13、将十进制 IP 地址转换为二进制的 IP 地址
# echo 192.168.3.33 | sed -e 's/\./;/g' -e 's/^/obase=2;ibase=10;/' | bc | xargs printf "%08d." | sed 's/.$/\n/'
# echo "obase=2;ibase=10;192;168;3;33" | bc | xargs printf "%08d." | sed 's/.$/\n/'
14、删除行首两个字符
# sed 's/^..//'
# tail -c +3
15、删除行尾两个字符
# sed 's/..$//'
# head -c -2
16、把字符串中的大写A替换成小写A
# sed 's/A/a/g'
# tr A a
17、判断字符串是否以 A 开头
if grep -Eq '^A'; then
if [ "$(echo $str | sed 's/^A//')" != "$str" ];then
if [ "${str#A}" != "$str" ]; then
18、判断字符串是否以 A 结尾
if grep -Eq 'A$'; then
if [ "$(echo $str | sed 's/A$//')" != "$str" ];then
if [ "${str%A}" != "$str" ]; then
19、截取字符串前面两个字符
# head -c 2
# grep -oE '^..'
# cut -c 1-2
# sed -r 's/^(..).*$/\1/'
20、截取字符串后面两个字符
# grep -oE '..$'
# tail -c 2
# sed -r 's/^.*(..)$/\1/'
21、截取字符串中第3至第5个字符
# cut -c 3-5
# sed -r 's/^..(...).*$/\1/'
# head -c5 | tail -c3
22、截取字符串中第1,第3,第8至第10,第12至末尾的字符
# cut -c1,3,8-10,12-
# awk 'BEGIN{FS=""} { for(i=1;i<=NF;i++) {if (i==1 || i== 3 || (i>=8 && i<=10) || i>=12) print $i } }' | tr -d $'\n'
23、去除数据中的重复行
# sort -u
# sort | uniq
24、计算数据中相同的行出现的次数
# sort | uniq -c
25、进行大文件的切割,每个小文件为100M
# head -c 2G /dev/urandom > bigfile
# split -b104857600 bigfile bigfile_
26、查找文件中单词 bin 出现的次数
# grep -wo bin /etc/passwd | wc -l
27、删除文件空白行
# grep -vE '^$' /etc/ssh/sshd_config --不能删除有空格符的空白行
# grep -vE '^\s*$' /etc/ssh/sshd_config --可以删除有空格符的空白行
28、把/etc/passwd 中所有的/bin/bash 登录shell 替换成 /sbin/nologin
# sed -E 's#/bin/bash#/sbin/nologin#g' /etc/passwd
29、统计文件 /etc/passwd 各个单词出现的频率
# grep -oE '\w+' /etc/passwd | sort | uniq -c | sed -r 's/^ +//'
# cat /etc/passwd | sed 's/[:/ ]/\n/g' | sed '/^$/d' | sort | uniq -c | sed -E 's/^\s+//' | sort -k1,1n
# cat /etc/passwd | grep -Eo '\w+' | sort | uniq -c | sed -E 's/^\s+//' | sort -k1,1n
# cat /etc/passwd | sed 's/[:/ ]/\n/g' | sed '/^$/d' | sort | uniq -c | sort -t" " -k6,6n
30、字符串检测
# echo abcd | grep -oE '^[a-z]+$' --测试字符串是否纯小写
# echo 12344323 |grep -oE '^[0-9]+$' --测试字符串是否纯数字
# echo iiiIIII | grep -oE '^[a-zA-Z]+$' --测试字符串是否纯字母
# echo 3425 |grep -E '^(0|[1-9][0-9]*)$' --测试字符串是否非负整数
# echo 3 |grep -E '^[1-9][0-9]*$' --测试字符串是否正整数
# echo -23 |grep -E '^-[1-9][0-9]*$' --测试字符串是否负整数
# echo 0 | grep -E '^(-[1-9][0-9]*)|(0|[1-9][0-9]*)$' --测试字符串是否整数
# echo -0.30000 | grep -E '^(-[1-9][0-9]*|[+-]?0|[1-9][0-9]*)\.[0-9]+$' --测试字符串是否小数
# echo _9kdj_324kdsd_dk | grep '^[a-zA-Z_][a-zA-Z0-9_]*$' --测试字符串是否只包含字母、数字、下划线,而且不以数字开头