1、总结sed和awk的详细用法;

sed
Sed本质上是一个编辑器,但是它是非交互式的;同时它又是面向字符流的,输入的字符流经过sed的处理后输出。
Sed本身是一个管道命令,可以分析standard input的,主要是用来分析关键字的使用、统计等,此外还可以将数据进行替换、删除、选取特定行等功能
格式:sed [option] ... 'script' inputfile...
script:
'地址命令'
常用选项:
-n:不输出模式中的内容至屏幕,只列出经过sed处理过的那一行。
-e:多点编辑,直接在命令行模式上进行sed的动作编辑。
-f:将sed的动作写在一个文件内,-f filename则可以执行filename内的sed 动作。
-r:支持使用扩展正则表达式;
-i:直接修改读取的文件内容,而不是由屏幕输出。
地址定界:
(1)不给地址:对全文进行处理;
(2)单地址:
#:指定的行;
/pattern/:被此处模式所能够匹配到的每一行;
(3)地址范围:
#,#
#,+#
/part1/,/part2/
编辑命令:
d:删除
p:显示模式空间中的内容
a \text:在行后面追加文本;支持使用\n实现多行追加;
i \text:在行前面插入文本;支持使用\n实现多行插入;
c \text:替换行为单行或多行文本;
w /path/to/somefile:保存模式空间匹配到的行至指定文件中;
r /path/from/some:读取指定文件的文本流至模式空间中匹配到的行的行后;
=:为模式空间中的行打印行号;
!:取反条件;
s///:支持使用其它分隔符,s@@@,S###;
替换标记:
g:行内全局替换;
p:显示替换成功的行;
w /PATH/TO/SOMEFILE:将替换成功的结果保存至指定文件中;
常用案例
以行为单位的新增加删除功能
1、nl /etc/passwd | sed '2,5d'
说明:
sed的动作为'2,5d',d就是删除,命令运行的结果就是把2~5行给删除。
sed后面接的动作,必须以''两个单引号括住。
如果只想删除第二行,命令就是nl /etc/passwd | sed '2d'
如果想删除第2行到最后一行,可以这么写:nl /etc/passwd | sed '2,$d'
2、nl /etc/passwd | sed '2a play game'
说明:
命令执行效果就是在第二行后面(也就是第三行)加上“play game”字样
如果想在第二行前面加上字符器,可以这样:
nl /etc/passwd | sed '2i play game'
注:2a中的a追加的意思,指第二行后面,而2i中的i是插入的意思,指第二行的前面。
3、nl /etc/passwd | sed '2a play game or ...\nplay football'
说明:
命令执行结果是在第二行后面加入2行字。
在每一行的后面必须以\n来进行新行的增加
以行为单位的替换与显示功能
1、nl /etc/passwd | sed '2,5c No 2~5 number'
说明:
命令的执行效果是将第2~5行的内容替换成"No 2~5 number"
2、nl /etc/passwd | sed -n '5,7p'
说明:
命令的执行效果是仅打印出文件中的第5~7行
命令中的-n代表是的安静模式!
3、sed 's/要被替换的内容/新内容/g'
说明:
命令执行的效果就是替换掉指定内容
4、记录一次获取IP地址的过程
第一步:先查询IP
/sbin/ifconfig eth0
注:目的是要获取IP数据,那么先利用关键字找出那一行
第二步:利用关键字配置grep选取出关键的一行数据
/sbin/ifconfig eth0 | grep 'inet addr'
注:因为只需要IP数据,所以接下来就是把不需要的内容删除,需要一个正则表达式来帮助实现:
^.*inet addr
第三步:将IP前面的部分予以删除
/sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*inet addr://g'
注:上面的命令就是把IP前面的数据删除掉了,接下来就是把IP后面的数据也删除,此时的正则表达式是:
Bcast.*$
第四步:将IP后面的部分予以删除
/sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*inet addr://g' | sed 's/Bcast.*$//g'
这样就把IP地址截取出来了。
直接修改文件内容(慎重)
1、sed -i '$a #This is a test' test.txt
说明:
命令的执行结果是在test.txt最后一行加入“This is a test”
由于$代表的是最后一行,而a的操作是新增,因此该文件最后新增。
awk
功能:awk是一个数据处理工具。相比于sed常常用于一整行的处理,awk则比较倾向于将一行分成数个“字段”来处理。因此,awk相当适合处理小型数据的数据处理。
基本语法:
awk [options] 'program' FILE ...
program:PATTERN {ACTION STATEMENTS}
多个语句之间用分号分隔
print,printf
选项:
-F:指明输入时用到的字段分隔符;
-v var=value:自定义变量;
1、print
print item1, item2, ...
要点:
(1)逗号分隔符;
(2)输出的各item可以是字符串,也可以是数值;当前记录的字段、变量或awk的表达式;
(3)如省略item,相当于print $0;
2、变量
(1)内建变量
FS:input field seperator,输入分隔符,默认为空白字符;
OFS:output field seperator,输出分隔符,默认为空白字符;
RS:input record sepeator,输入时的换行符;
ORS:output record seperator,输出时的换行符;
NF:number of field,字段数量
{print NF}, {print $NF}
NR:number of record,行数;
FNR:各文件分别计数;行数;
FILENAME:当前文件名;
ARGC:命令行参数的个数;
ARGV:数组,保存的是命令行所给定的各参数;
(2)自定义变量
-v var=value 
变量名区分字符大小写
在program中直接定义
3、printf命令
格式化输出:printf FORMAT, item1, item2, ...
(1)FORMAT必须给出;
(2)不会自动换行,需要显式给出换行控制符,\n 
(3)FORMAT中需要分别为后面的每个item指定一个格式化符号;
格式符:
%c:显示字符的ASCII码;
%d,%i:显示十进制整数;
%e,%E:科学计数法数值显示;
%f:显示为浮点数;
%g,%G:以科学计数或浮点形式显示数值;
%s:显示字符串;
%u:无符号整数;
%%:显示%自身;
修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;
%3.1f
-:左对齐
+:显示数值的符号
4、PATTERN
(1)empty:空模式,匹配每一行;
(2)/regular expression/:仅处理能够被此处模式匹配到的行;
(3)relational expression:关系表达式;结果有“真”有“假”;结果为“真”才会被处理
真:结果为非0值,非空字符串;
(4)line ranges:行范围,
startline,endline:/pat1/,/pat2/
注意:不支持直接给出数字的格式
(5)BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次;
END{}:仅在文本处理完成之后执行一次;
5、常用的action
(1)Expressions
(2)Control statements:if,while等;
(3)Compound statements:组合语句;
(4)input statements 
(5)output statements
6、控制语句
(1)if-else
语法:if(condition) statement [else statement]
使用场景:对awk取得的整行或某个字段做条件判断;
示例:
awk -F: '{if($3>=500) {printf "Common user:%s\n",$1} else {printf "root or Sysuser:%s\n",$1}}' /etc/passwd
awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
awk '{if(NF>5) print $0}' /etc/fstab
df -h | awk -F% '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}'
(2)while循环
语法:while(condition) statement
条件 “真”,进行循环;条件“假”,退出循环;
使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用;
示例:
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)}; i++}}' /etc/grub2.cfg
(3)do-while循环
语法:do statement while(condition)
意义:至少执行一次循环体
(4)for循环
语法:for(expr1;expr2;expr3) statement
for(variable assignment;condition;iteration process){for-body}
示例:
awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}' /etc/grub2.cfg 
特殊用法:
能够遍历数组中的元素;
语法:for(var in array){for-body}
(5)switch语句
语法:switch(expression) {case VALUE1 or /REGEXP/:statement;case VALUE2 or /REGEXP2/:statement;...;default:statement}
(6)next
提前结束对本行的处理而直接进入下一行;
示例:
awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd
7、array
关联数组:array[index-expression]
index-expression: 
(1)可使用任意字符串,字符串要使用双引号;
(2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;
若要判断数组中是否存在某元素,使用“index in array”格式进行;
weekdays[mon]="Monday"
若要遍历数组中的每个元素,要使用for循环;
for(var in array){for-body}
示例:
awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}'
8、其它常见示例
(1)统计/etc/fstab文件中每个文件系统类型出现的次数;
awk '/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab
(2)统计/etc/fstab文件中每个单词出现的次数;
 awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab

2、删除/boot/grub/grub.conf文件中所有行的行首的空白字符;

[root@localhost ~]# sed 's/^[[:space:]]*//g' /boot/grub/grub.conf

3、删除/etc/fstab文件中所有以#开头,后跟至少一个空白字符的行的行首的#和空白字符;

[root@localhost ~]# sed 's/^#[[:space:]]\+//' /etc/fstab

4、把/etc/fstab文件的奇数行另存为/tmp/fstab.3;

[root@localhost ~]# sed 'n;d' /etc/fstab > /etc/fstab.3

5、echo一个文件路径给sed命令,取出其基名;进一步地,取出其路径名;

[root@localhost ~]# echo "/etc/sysconfig/network/" | sed -r 's@^/.*/([^/]+)/?@\1@g'
[root@localhost ~]# echo "/etc/sysconfig/network/" | sed 's#[^/]\+/\?$##'

6、统计指定文件中所有行中每个单词出现的次数;

[root@localhost ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab

7、统计当前系统上所有tcp连接的各种状态的个数;

[root@localhost ~]# netstat -tan | awk 'FNR>2{print $NF}' | sort | uniq -c

8、统计指定的web访问日志中各ip的资源访问次数:

[root@localhost ~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log

9、写一个脚本:定义一个数组,数组元素为/var/log目录下所有以.log结尾的文件的名字;显示每个文件的行数;

[root@localhost ~]# vim line.sh
#!/bin/bash
test=`ls /var/log/*log`
for i in $test
do
    wc -l $i
done

10、写一个脚本,能从所有同学中随机挑选一个同学回答问题;进一步地:可接受一个参数,做为要挑选的同学的个数;

[[root@localhost ~]# vim student.sh
#!/bin/bash
stu=(zhangsan lisi wangwu zhaoliu liuhu zhaosi)
i=$[$RANDOM % ${#stu[@]}]
echo ${stu[i]}
[root@localhost ~]# vim students.sh
#!/bin/bash
stu=(zhangsan lisi wangwu zhaoliu liuhu zhaosi)
read -p "Please input the number of students:" num
if [[ $num -le ${#stu[@]} ]]
then
    for ((i=0;i<num;i++))
    do
        x=$[$RANDOM % ${#stu[@]}]
        echo ${stu[$x]}
        stu[$x]=${stu[${#stu[@]}-1]}
        unset stu[${#stu[@]}-1]
    done
else
    echo "input error!"
fi

11、授权centos用户可以运行fdisk命令完成磁盘管理,以及使用mkfs或mke2fs实现文件系统管理;

[root@localhost ~]# vim /etc/sudoers
centos  ALL=(root)   NOPASSWD: /sbin/fdisk, /sbin/mke2fs, /sbin/mkfs

12、授权gentoo用户可以运行逻辑卷管理的相关命令;

[root@localhost ~]# vim /etc/sudoers
gentoo ALL=(root) lvm

13、基于pam_time.so模块,限制用户通过sshd服务远程登录只能在工作时间进行;

[root@localhost ~]# vim /etc/pam.d/sshd
account    required pam_time.so
[root@localhost ~]# vim /etc/security/time.conf 
*;*;*;MoTuWeThFr0900-1800#表示工作时间9点到下午6点允许访问ssh

14、基于pam_listfile.so模块,定义仅某些用户,或某些组内的用户可登录系统;"

[root@localhost ~]# vim /etc/sshd_userlist
root
centos
gentoo
[root@localhost ~]# chmod 600 /etc/sshd_userlist 
[root@localhost ~]# chown root /etc/sshd_userlist 
[root@localhost ~]# vim /etc/pam.d/sshd
添加
auth        required pam_listfile.so item=user sense=allow file=/etc/sshd_userlist onerr=succeed