sed和awk和数组实践-week15

栏目: 服务器 · 发布时间: 8年前

内容简介:sed和awk和数组实践-week15

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

(1) sed

sed:Stream EDitor,流编辑器,行编辑器

基本原理:

一次从文本中读取一行,放到sed自己的工作车间加工, 该工作车间叫做模式空间(pattern space)

判断该行是否符合过滤模式,

  • 如果符合过滤模式:
    1. 送往标准输出(终端)
    2. 执行编辑操作, 从模式空间中处理以后,处理过后送到标准输出(不一定有输出,比如删除操作)
  • 如果不能被模式过滤,不做任何操作,直接送到标准输出

也可以理解为模式空间的的内容,不管匹配不匹配都会送到标准输出,但删除(d)操作例外

基本语法:

sed [OPTION]… ‘script’ [input-file] …

script:
        地址定界编辑命令

      常用选项:
        -n:不输出模式空间中的内容至屏幕;默认是输出的
        -e script, --expression=script:多点编辑;同时执行多个编辑命令
        -f  /PATH/TO/SED_SCRIPT_FILE :  sed脚本,每行一个编辑命令;
        -r, --regexp-extended:支持使用扩展正则表达式;
        -i[SUFFIX], --in-place[=SUFFIX]:直接编辑原文件 ;危险:修改前先备份  

    地址定界:
    (1) 空地址:对全文进行处理;
    (2) 单地址:
        #:指定行;
        /pattern/:被此模式所匹配到的每一行;
    (3) 地址范围
        #,#:             从第#行到第#行
        #,+#:            从第#行开始,一直到向下的#行
        #,/pat1/         从指定行开始到第一次被patteren匹配的行结束
        /pat1/,/pat2/     从第一次pattern匹配的行,到第一次被pattern匹配的行
        $:最后一行
    (4) 步进:~
        1~2:所有奇数行
        2~2:所有偶数行  

    编辑命令:
        d:删除模式空间中的内容
        p:显示模式空间中的内容;
        a  \text:在行后面追加文本“text”,支持使用\n实现多行追加; 
        i  \text:在行前面插入文本“text”,支持使用\n实现多行插入; 
        c  \text:把匹配到的行替换为此处指定的文本“text”;
        w /PATH/TO/SOMEFILE:保存模式空间匹配到的行至指定的文件中;
        r  /PATH/FROM/SOMEFILE:读取指定文件的内容至当前文件被模式匹配到的行后面;文件合并;
        =:为模式匹配到的行打印行号;
        !:条件取反;
            地址定界!编辑命令;
        s///:查找替换,其分隔符可自行指定,常用的有s@@@, s###等;
            替换标记:
                g:全局替换;
                w /PATH/TO/SOMEFILE:将替换成功的结果保存至指定文件中;
                p:显示替换成功的行;
    高级编辑命令:  
            保持空间 hold space
        h:把模式空间中的内容覆盖至保持空间中;
        H:把模式空间中的内容追加至保持空间中;
        g:把保持空间中的内容覆盖至模式空间中;
        G:把保持空间中的内容追加至模式空间中;
        x:把模式空间中的内容与保持空间中的内容互换;
        n:覆盖读取匹配到的行的下一行至模式空间中;  覆盖原行
        N:追加读取匹配到的行的下一行至模式空间中; 追加原行
        d:删除模式空间中的行;
        D:删除多行模式空间中的所有行;

(2) awk

awk:报告生成器,格式化文本输出

gawk – pattern scanning and processing language

模式扫描及编程语言

基本用法

gawk [options] ‘program’ FILE …

program: PATTERN{ACTION STATEMENTS}

模式{动作语句};

语句之间用分号分隔

PATTERN:  主要用来定界
    awk本身实现文件遍历一次读取一行文本,按输入分隔符切片,每一片放在内置变量中($1,$2...),整行用$0表示,支持条件判断,循环(字段间循环)  

print, printf
选项:
-F:指明输入时用到的字段分隔符;默认空白字符
-v var=value: 自定义变量;

1、print

    print item1, item2, ...

    要点:
        (1) 逗号分隔符;
        (2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式;
        (3) 如省略item,相当于print $0; 
示例: 
[root@localhost ~]# tail -3 /etc/fstab | awk '{print $2,$3}'
/ xfs
/boot xfs
swap swap

[root@localhost ~]# tail -3 /etc/fstab | awk '{print "hello",$2,$3,6}'
hello / xfs 6
hello /boot xfs 6
hello swap swap 6

变量不能放到引号内
[root@localhost ~]# tail -3 /etc/fstab | awk '{print "hello:$1"}'
hello:$1
hello:$1
hello:$1
[root@localhost ~]# tail -3 /etc/fstab | awk '{print "hello:"$1}'
hello:UUID=fcaeeb31-be94-4915-a2cd-0663a733f140
hello:UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55
hello:UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565

输入整行
[root@localhost ~]# tail -3 /etc/fstab | awk '{print}'
UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 /                       xfs     defaults        0 0
UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55 /boot                   xfs     defaults        0 0
UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565 swap                    swap    defaults        0 0
每行输入空白
[root@localhost ~]# tail -3 /etc/fstab | awk '{print ""}'

2、变量
2.1 内建变量
    FS:input field seperator输入字段分隔符,默认为空白字符;
    OFS:output field seperator输入字段分隔符,默认为空白字符;
    RS:input record seperator行分隔符,输入时的换行符;
    ORS:output record seperator,输出时的换行符;

    NF:number of field,字段数量         变量前不加$
        {print NF},  字段数量
{print $NF}   显示的是字段  不要混淆
    NR:number of record, 行数;
    FNR:各文件分别计数;行数;

    FILENAME:当前文件名;

    ARGC:命令行参数的个数;
    ARGV:数组,保存的是命令行所给定的各参数;  

示例:   
指明输入文件字段分隔符
[root@localhost ~]# awk -v FS=':' '{print $1}' /etc/passwd
root
bin
daemon
或直接使用选项,效果相同
[root@localhost ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
指明输入分隔符和输出分隔符
[root@localhost ~]# awk -v FS=':' -v OFS=':'  '{print $1,$3,$7}' /etc/passwd
root:0:/bin/bash
bin:1:/sbin/nologin
daemon:2:/sbin/nologin

指定行分隔符, 遇到空格和原换行符都换行, 了解
[root@localhost ~]# awk -v RS=' ' '{print}' /etc/passwd
指定输出行分隔符, 结果比较诡异, 空格分割的右#号隔开, 原换行符依然解析为换行
[root@localhost ~]# awk -v RS=' ' -v ORS='#' '{print}' /etc/passwd

输入每行字段个数
[root@localhost ~]# awk '{print NF}' /etc/fstab 
0
1
2
10
1
9
12
1
6
6
6

显示行数, 此处为单个文件,表示为行编号
[root@localhost ~]# awk '{print NR}' /etc/fstab 
1
2
3
4
5
6
7
8
9
10
11
两个文件的行数,14行
[root@localhost ~]# awk '{print NR}' /etc/fstab /etc/issue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
单独计算行数
[root@localhost ~]# awk '{print FNR}' /etc/fstab /etc/issue 
1
2
3
4
5
6
7
8
9
10
11
1
2
3
显示当前正在处理的文件名
[root@localhost ~]# awk '{print FILENAME}' /etc/fstab /etc/issue 
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/issue
/etc/issue
/etc/issue

命令行参数个数,及 各参数
[root@localhost ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue
3
[root@localhost ~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue
awk
[root@localhost ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue
/etc/fstab
[root@localhost ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue
/etc/issue

2.2 自定义变量
    (1) -v var=value

        变量名区分字符大小写;

    (2) 在program中直接定义
注意:  对文件不做处理时,文件可不带  

示例: 
输出自定义变量
[root@localhost ~]# awk -v test='hello awk' '{print test}'  /etc/fstab
hello awk
hello awk
hello awk
hello awk
hello awk
hello awk
hello awk
hello awk
hello awk
hello awk
hello awk
自定义变量,不带文件
[root@localhost ~]# awk -v test='hello awk' 'BEGIN{print test}'
hello awk
自定义变量,在程序中定义
[root@localhost ~]# awk 'BEGIN{test="hello awk";print test}'
hello awk

3、printf命令

    格式化输出:printf FORMAT, item1, item2, ...
                                FORMAT : 占位
        (1) FORMAT必须给出; 
        (2) 不会自动换行,需要显式给出换行控制符,\n
        (3) FORMAT中需要分别为后面的每个item指定一个格式化符号;

        格式符: 可加入字符串
            %c: 显示字符的ASCII码;
            %d, %i: 显示十进制整数;
            %e, %E: 科学计数法数值显示;
            %f:显示为浮点数;
            %g, %G:以科学计数法或浮点形式显示数值;
            %s:显示字符串;
            %u:无符号整数;
            %%: 显示%自身;

        修饰符:
            #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;
                %3.1f
            -: 左对齐
            +:显示数值的符号

示例: 
[root@localhost ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
daemon
[root@localhost ~]# awk -F: '{printf "username: %s\n",$1}' /etc/passwd
username: root
username: bin
username: daemon
[root@localhost ~]# awk -F: '{printf "username: %s,uid: %d\n",$1,$3}' /etc/passwd
username: root,uid: 0
username: bin,uid: 1
username: daemon,uid: 2

右对齐
[root@localhost ~]# awk -F: '{printf "username: %15s,uid: %d\n",$1,$3}' /etc/passwd
username:            root,uid: 0
username:             bin,uid: 1
username:          daemon,uid: 2
左对齐
[root@localhost ~]# awk -F: '{printf "username: %-15s,uid: %d\n",$1,$3}' /etc/passwd
username: root           ,uid: 0
username: bin            ,uid: 1
username: daemon         ,uid: 2

4、操作符

    算术操作符:
        x+y, x-y, x*y, x/y, x^y, x%y
        -x : 正数转为负数
        +x: 转换为数值;

    字符串操作符:没有符号的操作符,字符串连接

    赋值操作符:
        =, +=, -=, *=, /=, %=, ^=
        ++, --

    比较操作符:
        >, >=, <, <=, !=, ==

    模式匹配符:
        ~:是否匹配
        !~:是否不匹配

    逻辑操作符:
        &&
        ||
        !

    函数调用:
        function_name(argu1, argu2, ...)

    条件表达式:
        selector?if-true-expression:if-false-expression

        # awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd

示例: 
[root@localhost ~]# awk -F: '{$3>=1000?usertype="common user":usertype="sysadmin or sysuser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd
           root:sysadmin or sysuser
            bin:sysadmin or sysuser

5、PATTERN

    (1) empty:空模式,匹配每一行;
    (2) /regular expression/:仅处理能够被此处的模式匹配到的行;
    (3) relational expression: 关系表达式;结果有“真”有“假”;结果为“真”才会被处理;
        真:结果为非0值,非空字符串;
    (4) line ranges:行范围,
        startline,endline:/pat1/,/pat2/

        注意: 不支持直接给出数字的格式
        ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
    (5) BEGIN/END模式
        BEGIN{}: 仅在开始处理文件中的文本之前执行一次;
        END{}:仅在文本处理完成之后执行一次;

示例: 

取UUID开头的行
[root@localhost ~]# awk '/^UUID/{print $1}' /etc/fstab
UUID=fcaeeb31-be94-4915-a2cd-0663a733f140
UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55
UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565
取非UUID开头的行
[root@localhost ~]# awk '!/^UUID/{print $1}' /etc/fstab

#
#
#
#
#
#
#
查找id对于1000的用户
[root@localhost ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
han 1000
user101 1001
取出默认 shell 为bash的用户  条件表达式
[root@localhost ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
han /bin/bash
取出默认shell为bash的用户  模式匹配
[root@localhost ~]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd
root /bin/bash
han /bin/bash
定界(模式)
[root@localhost ~]# awk -F: '/^root/,/^daemon/{print $1}' /etc/passwd
root
bin
daemon
定界(行号)
[root@localhost ~]# awk -F: '(NR>=1&&NR<=3){print $1}' /etc/passwd
root
bin
daemon
表头和表尾
[root@localhost ~]# awk -F: 'BEGIN{print "      username      uid      \n------------------------"}{print $1,$3}END{print "==============="}' /etc/passwd
      username      uid      
------------------------
root 0
bin 1
daemon 2
===============

6、常用的action

    (1) Expressions    表达式
    (2) Control statements:if, while等;   控制语句
    (3) Compound statements:组合语句; 多个语句作为单个代码块
    (4) input statements  输入语句
    (5) output statements  输出语句

7、控制语句

    if(condition) {statments} 
    if(condition) {statments} else {statements}
    while(conditon) {statments}
    do {statements} while(condition)
    for(expr1;expr2;expr3) {statements}
    break
    continue
    delete array[index]  从数组中删除某个元素
    delete array   删除整个数组
    exit   退出
    { statements }  组合语句

7.1 if-else

    语法:if(condition) statement [else statement]
                         注意: 有else语句时,需使用花括号

~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
默认shell为bash
        ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
行数大于5
        ~]# awk '{if(NF>5) print $0}' /etc/fstab
设备使用率大于20%
        ~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}'

        使用场景:对awk取得的整行或某个字段做条件判断;
示例: 
单分支
取用户id大于1000的用户
[root@localhost ~]# awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd
han 1000
user101 1001
取默认shell为bash
[root@localhost ~]# awk -F: '{if($NF=="/bin/bash")print $1,$7}' /etc/passwd
root /bin/bash
han /bin/bash
每行字段数大于5的行
[root@localhost ~]# awk '{if(NF>5)print $0}' /etc/fstab 
# Created by anaconda on Sat Aug 20 07:19:36 2016
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 /                       xfs     defaults        0 0
UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55 /boot                   xfs     defaults        0 0
UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565 swap                    swap    defaults        0 0


双分支
[root@localhost ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n", $1} else {printf "root or sysuser: %s\n",$1}}' /etc/passwd
root or sysuser: root
root or sysuser: bin
查看硬盘使用情况,大于20%
[root@localhost ~]# df -h | awk -F% '/^\/dev/{print $1}' | awk '{if($NF>=20)print $1,$NF}'
/dev/sda2 37
/dev/sda1 29
/dev/sr0 100


7.2 while循环
    语法:while(condition) statement
        条件“真”,进入循环;条件“假”,退出循环;

    使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用;  

示例: 
显示每行的每一个字段,和字段的字符个数
                ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
显示每行的每一个字段,和字段的字符个数(长度大于等于7)
                ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg

练习1, 每行的每字段的长度
[root@localhost ~]# awk '/^[[:space:]]*linux16/{print}'  /etc/grub2.cfg 
    linux16 /vmlinuz-3.10.104-1.el7 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 ro rhgb quiet LANG=en_US.UTF-8
    linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 ro rhgb quiet LANG=en_US.UTF-8
    linux16 /vmlinuz-0-rescue-f6f5e947dd374a46b0b7238d0ae4becb root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 ro rhgb quiet
[root@localhost ~]# 
linux16 7^C
[root@localhost ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}'  /etc/grub2.cfg 
linux16 7
/vmlinuz-3.10.104-1.el7 23
root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-3.10.0-327.el7.x86_64 30
root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-f6f5e947dd374a46b0b7238d0ae4becb 50
root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46
ro 2
rhgb 4
quiet 5
大于等于7的字段:
[root@localhost ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=7){print $i,length($i)};i++}}'  /etc/grub2.cfg 
linux16 7
/vmlinuz-3.10.104-1.el7 23
root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-3.10.0-327.el7.x86_64 30
root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-f6f5e947dd374a46b0b7238d0ae4becb 50
root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46


7.3 do-while循环
    语法:do statement while(condition)
        意义:至少执行一次循环体

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

7.5 switch语句
    语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}
              用于字符串比较判断

7.6 break和continue              针对的是字段
    break [n]  跳出n层循环
    continue  进入下一轮循环

7.7 next    控制awk的内生循环   针对的是行

    提前结束对本行的处理而直接进入下一行;
显示偶数行
    ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd

8、array

    关联数组:array[index-expression]

        index-expression:
            (1) 可使用任意字符串;字符串要使用双引号;
            (2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;数值运算的话会当成0

            若要判断数组中是否存在某元素,要使用"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]}}'

[root@localhost ~]# awk 'BEGIN{weekday["mon"]="monday";weekday["tue"]="tuesday";for( i in weekday)  {print weekday[i]}}'
tuesday
monday

注意:var会遍历array的每个索引;

使用该特性,计算每个状态的次数
state["LISTEN"]++
state["ESTABLISHED"]++

~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'

[root@localhost ~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}'
LISTEN 2
ESTABLISHED 1


~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
统计httpd日志中每个ip的访问情况
[root@localhost ~]# awk '/^[^:]/{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
172.16.0.1 143


练习1:统计/etc/fstab文件中每个文件系统类型出现的次数;
~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab

[root@localhost ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab 
swap 1
xfs 2

练习2:统计指定文件中每个单词出现的次数;
~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab

9、函数
9.1 内置函数
    数值处理:
        rand():返回0和1之间一个随机数;
注意: 只有第一次是随机的

[root@localhost ~]# awk 'BEGIN{print rand()}'
0.237788
[root@localhost ~]# awk 'BEGIN{print rand()}'
0.237788

    字符串处理:
        length([s]):返回指定字符串的长度;
        sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容;
        gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容;

        split(s,a[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;
awk数组从1开始编号
        ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'

9.2 自定义函数
推荐:     《sed和awk》

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

[root@node1 ~]# sed  's#^[[:space:]]\+##' /boot/grub/grub.conf
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/mapper/VolGroup-lv_root
#          initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS 6 (2.6.32-504.el6.x86_64)
root (hd0,0)
kernel /vmlinuz-2.6.32-504.el6.x86_64 ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=VolGroup/lv_root  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32-504.el6.x86_64.img

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

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

#
/etc/fstab
Created by anaconda on Sun Apr 23 14:26:50 2017
#
Accessible filesystems, by reference, are maintained under '/dev/disk'
See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/VolGroup-lv_root /                       ext4    defaults        1 1
UUID=2bf153ef-3ae1-4a1f-8140-813aead76d0a /boot                   ext4    defaults        1 2
/dev/mapper/VolGroup-lv_home /home                   ext4    defaults        1 2
/dev/mapper/VolGroup-lv_swap swap                    swap    defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0

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

[root@node1 ~]# sed -n '1~2w /tmp/fstab.3' /etc/fstab
[root@node1 ~]# cat /tmp/fstab.3

# /etc/fstab
#
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
/dev/mapper/VolGroup-lv_root /                       ext4    defaults        1 1
/dev/mapper/VolGroup-lv_home /home                   ext4    defaults        1 2
tmpfs                   /dev/shm                tmpfs   defaults        0 0
sysfs                   /sys                    sysfs   defaults        0 0

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

取基名:

[root@node1 ~]# echo "/etc/fstab" | sed -r   's@.*/(.*)@\1@'
fstab
[root@node1 ~]# echo "/var/name/html" | sed -r   's@.*/(.*)@\1@'
html

取路径名:

[root@node1 ~]# echo "/var/www/html" | sed -r   's@(.*/).*@\1@'
/var/www/
[root@node1 ~]# echo "/etc/fstab" | sed -r   's@(.*/).*@\1@'
/etc/

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

[root@node1 ~]# awk '{i=1;while(i<=NF){word[$i]++;i++}}END{for(i in word){print i,word[i]}}' /etc/fstab
mount(8) 1
Accessible 1
pages 1
reference, 1
/dev/pts 1
/dev/mapper/VolGroup-lv_swap 1
info 1
devpts 2
tmpfs 2
/dev/mapper/VolGroup-lv_home 1
blkid(8) 1
and/or 1
# 7
gid=5,mode=620 1
Sun 1
/ 1
anaconda 1
/proc 1
0 10
1 4
2 2
findfs(8), 1
on 1
/boot 1
Apr 1
/dev/mapper/VolGroup-lv_root 1
/etc/fstab 1
sysfs 2
2017 1
are 1
more 1
/sys 1
'/dev/disk' 1
/home 1
14:26:50 1
defaults 7
proc 2
ext4 3
by 2
swap 2
/dev/shm 1
23 1
for 1
man 1
See 1
filesystems, 1
UUID=2bf153ef-3ae1-4a1f-8140-813aead76d0a 1
maintained 1
Created 1
under 1
fstab(5), 1

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

~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}'
ESTABLISHED 3
LISTEN 14

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

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

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

#!/bin/bash
# description: 显示/var/log下所有以.log结尾的文件对应的行数
# author: han

declare -a filenames
filenames=(/var/log/*.log)

for((i=0;i<${#filenames[*]};i++));do
        filename=`basename ${filenames[$i]}`
        lines=`wc -l ${filenames[$i]} | cut -d' ' -f1`
        printf "%-30s %-5s\n" $filename $lines

done

执行结果: 
]# bash file_lines.sh
anaconda.ifcfg.log             168
anaconda.log                   257
anaconda.program.log           387
anaconda.storage.log           1466
anaconda.yum.log               224
boot.log                       45
dracut.log                     1639
heartbeat.log                  5719
mysqld.log                     128
yum.log                        82

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

]# cat choose.sh
#!/bin/bash
# 随机抽选一个或几个同学
# han


#定义一个数组,保存同学名字
declare -a names
names=("张三" "李四" "王五" "刘六" "田七" "韩信" "匆匆" "忙忙" "豆豆" "五行")
total=${#names[*]}


#定义一个函数,判断新生成的随机数是否已经在下标列表数组choices中,存在则返回3,
function isexited(){
        for((j=0;j<${#choices[*]};j++));do
               if [ ${choices[$j]} -eq $choice ];then
                     return 3
               fi
        done
}


#参数大于一个时,提示使用方法
[ $# -gt 1 ] && echo "Usage $0 [1-${#names[*]}]" && exit 1

#没有参数时,默认显示一位同学
if [ $# -eq 0 ];then
        choice=$[$RANDOM%${total}]
        echo  "${names[$choice]} "
#有一个参数时
else
        #参数非数字时,退出
        if [[ ! $1 =~ [0-9] ]];then
                echo "Invalid agrument"
                exit 2
        fi
        #参数大小在正确范围时
        #定义一个数组,存放出现过的学生下标
        declare -a choices
        if [ $1 -ge 1 ] && [ $1 -le $total ];then
        #循环$1次
                for((i=0;i<$1;i++));do
        #生成随机数,作为数组下标
                        choice=$[$RANDOM%${total}]
        #调用函数,判断该下标是否在choices数组中
                        isexited
        #判断函数返回值,已存在则将i自减1,使得下个循环变量依然为i,保证下标存在时有多一次循环机会,保证最后choices组有$1个元素
                        if [ $? -eq 3 ];then
                                let i--
                        else
                                choices[$i]=$choice
                        fi
                done
        #根据下标显示挑选出的同学
        for i in ${choices[*]};do
                echo -n "${names[$i]} "
        done
        echo

        else
                echo "Usage $0 [1-${#names[*]}]" && exit 1
        fi

fi

效果

[root@node1 scripts]# ./choose.sh
忙忙
[root@node1 scripts]# ./choose.sh 3
匆匆 韩信 刘六
[root@node1 scripts]# ./choose.sh 9
李四 五行 忙忙 豆豆 匆匆 王五 刘六 韩信 张三
[root@node1 scripts]# ./choose.sh 9
张三 韩信 刘六 忙忙 王五 匆匆 李四 五行 田七
[root@node1 scripts]# ./choose.sh 12
Usage ./choose.sh [1-10]

备注: 此题用的方法有些麻烦,看了下其他同学的方法,有个非常简单记录在此:

#!/bin/bash
#
students=(a b c d e f g h i j k)
read -t 5 -p "Please input the number of students: " num
if [[ $num -le ${#students[@]} ]]
then 
     for ((i=0;i<num;i++))
     do x=$[$RANDOM % ${#students[@]}]
        echo  ${students[$x]}
        students[$x]=${students[${#students[@]}-1]}
        unset students[${#students[@]}-1]     #这样删就不会再选到这个索引号
       #unset students[$x]  这个删除只删除了元素的值,但索引号仍在值为空
     done  
else echo "Error";exit
fi

备注: 大致思路看明白了,只是比较费解这种unset方法

另外一种彻底删除元素加索引的方法:

[root@node1 scripts]# files=(/etc/[Pp]*)
[root@node1 scripts]#  echo ${files[@]}
/etc/pam.d /etc/pango /etc/passwd /etc/passwd- /etc/pkcs11 /etc/pki /etc/plymouth /etc/pm /etc/popt.d /etc/postfix /etc/ppp /etc/printcap /etc/profile /etc/profile.d /etc/protocols
[root@node1 scripts]#  echo ${#files[@]}
15
#当前数组有15个元素

#删除特定索引的元素(同时删除索引)
[root@node1 scripts]# pos=3    #删除索引3的元素
[root@node1 scripts]# files=(${files[@]:0:$pos} ${files[@]:$(($pos + 1))})        
#通过数组切片将前3各元素的数组和从第4各元素开始的数组合并为一个数组
[root@node1 scripts]# echo ${#files[@]}
14
#此时元素各数为14
[root@node1 scripts]#  echo ${files[@]}
/etc/pam.d /etc/pango /etc/passwd /etc/pkcs11 /etc/pki /etc/plymouth /etc/pm /etc/popt.d /etc/postfix /etc/ppp /etc/printcap /etc/profile /etc/profile.d /etc/protocols
# 索引为3的元素/etc/passwd-已经被删除

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

root用户: 
]# visudo
centos  ALL=(ALL)       /sbin/fdisk,/sbin/mkfs,/sbin/mke2fs

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

[root@node1 ~]# visudo
gentoo  ALL=(ALL)       /sbin/pvs,/sbin/pvdisplay,/sbin/pvcreate,/sbin/vgs,/sbin/vgdisplay,/sbin/vgcreate,/sbin/vgextend,/sbin/vgreduce,/sbin/vgremove,/sbin/lvs
,/sbin/lvdisplay,/sbin/lvcreate,/sbin/lvremove,/sbin/lvextend,/sbin/resize2fs

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

需用到pam模块pam_time.so

1) ssh

]# vim /etc/pam.d/sshd
#%PAM-1.0
auth       required     pam_sepermit.so
auth       include      password-auth
account    required     pam_time.so     #添加该行
account    required     pam_nologin.so

...

2)配置time.conf

time.conf配置文件格式:services;ttys;users;times

services — pam服务名列表,可以ls /etc/pam.d查看

tty —终端名.

users —用户名

times —可以使用services 的时间段

]# vim /etc/security/time.conf
sshd;*;centos;MoTuWeThFr0900-1800  #centos用户只能在工作时间通过ssh远程登录

验证:

[centos@node1 ~]$ ssh centos@172.16.0.20
centos@172.16.0.20's password:
Connection closed by 172.16.0.20

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

创建允许访问的用户列表
[root@node1 ~]# vim /etc/sshd_userlist
root
centos
修改文件权限(非必须)
[root@node1 ~]# chmod 600 /etc/sshd_userlist

修改pam配置文件
[root@node1 ~]# vim /etc/pam.d/sshd
#%PAM-1.0
auth required pam_listfile.so item=user sense=allow file=/etc/sshd_userlist onerr=succeed
auth       required     pam_sepermit.so

验证:

centos可以访问
[centos@node1 ~]$ ssh centos@172.16.0.20
centos@172.16.0.20's password:
Last login: Sat May  6 17:04:12 2017 from node1.magedu.com  

fedora被拒绝访问
[root@node2 ~]# ssh fedora@172.16.0.20
fedora@172.16.0.20's password:
Permission denied, please try again.
fedora@172.16.0.20's password:
Permission denied, please try again.
fedora@172.16.0.20's password:

以上所述就是小编给大家介绍的《sed和awk和数组实践-week15》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Web Designer's Idea Book

The Web Designer's Idea Book

Patrick Mcneil / How / 2008-10-6 / USD 25.00

The Web Designer's Idea Book includes more than 700 websites arranged thematically, so you can find inspiration for layout, color, style and more. Author Patrick McNeil has cataloged more than 5,000 s......一起来看看 《The Web Designer's Idea Book》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具