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:

原創文章,作者:hansj,如若轉載,請注明出處:http://www.www58058.com/74840

(0)
hansjhansj
上一篇 2017-05-06 09:19
下一篇 2017-05-06

相關推薦

  • 搜索引擎的技術架構

    1. 搜索引擎的分類 搜索引擎按其工作方式主要可分為三種: 分別是全文搜索引擎(Full Text Search Engine) 目錄索引類搜索引擎(Search Index/Directory) 元搜索引擎(Meta Search Engine)。 ■ 全文搜索引擎  全文搜索引擎是名副其實的搜索引擎,國外具代表性的有Google、Fast/Al…

    Linux干貨 2015-11-18
  • 數據庫基礎

    數據庫基礎 一、數據模型 數據庫模型圖 1、層次模型、2、網狀模型、 3、關系模型二維關系: 表:就是一個關系及屬性的描述,如:學生(學好,姓名,性別,班級)       行:row, entity       列:colume,…

    Linux干貨 2016-10-19
  • Linux網站架構系列之Mysql—-部署篇

    原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://nolinux.blog.51cto.com/4824967/1321079   MySQL是一個關系型數據庫管理系統,由瑞典MySQL AB公司開發,目前屬于Oracle公司。MySQL所使用的SQL語言是用于…

    Linux干貨 2015-04-01
  • centos6安裝docker

    使用的操作系統是是centos6.3,按照官方的推薦的配置,把linux內核升級到3.8以上。安裝步驟如下: 1、升級內核版本(包含aufs) cd /etc/yum.repos.d     wget http://www.hop5.in/yum/el6/hop5.repo   …

    Linux干貨 2016-05-05
  • 馬哥教育網絡班20期+第2周課程練習

    馬哥教育網絡班20期+第2周課程練習 練習題: 1、Linux上的文件管理類命令都有哪些,其常用的使用方法及其相關示例演示。2、bash的工作特性之命令執行狀態返回值和命令行展開所涉及的內容及其示例演示。3、請使用命令行展開功能來完成以下練習:   (1)、創建/tmp目錄下的:a_c, a_d, b_c, b_d  …

    Linux干貨 2016-06-23

評論列表(1條)

  • PowerMichael
    PowerMichael 2017-05-07 22:58

    厲害,學習了。

欧美性久久久久