打开文件:
    # vim [option]... [FILE]...

ESC键:
    编辑模式-->输入模式:
        i: 在光标所在处的前方转换为输入模式
        a: 在光标所在的后方转换为输入模式
        o: 在光标所在行的下方新建一个空行并转换为输入模式

        I: 行首 
        A:行尾
        O: 光标所在行的上方新建一个空白行

    输入模式-->编辑模式
        ESC

    编辑模式-->末行模式
        :
    末行模式-->编辑模式
        ESC

    输入-->编辑-->末行

退出文件:
    :q! 不保存退出
    :wq 保存退出
    :x 保存退出
    :wq! 强制保存退出

    编辑模式保存退出:ZZ

编辑文本:

    光标移动:
        字符间移动:
            h,j,k,l
            #{h|j|k|l}: 跳#个字符

        单词间移动:
            w: 下一个单词词首
            e: 当前单词或下一个单词词尾
            b: 当前单词或前一个单词词首
            #{w|e|b}:

        行内移动:
            ^: 行首第一个非空白字符
            0:绝对行首
            $: 绝对行尾

        句子间移动:
            ) 
            (

        段落间移动:
            }
            {

        行间移动:
            #G: 直接跳转至第#行;
            G:最后一行

    编辑命令:
        x: 删除光标所在处的字符
        #x:

        d: 删除命令
            结合光标跳转字符使用,删除跳转范围内的字符
                w, b, e, 
                $, 0, ^
            #d
        dd: 删除光标所在行
        D: d$

        注意:最后一次删除的内容会被保存至缓冲区

        p: paste, 粘贴
            行级别:
                p: 粘贴于当前行下方
                P:             上
            小于行级别:
                p: 粘贴于当前光标所在处的后方
                P:                      前

        y: yank, 复制
            结合光标跳转字符使用,复制跳转范围内的字符
                w, b, e, 
                $, 0, ^
            #y
        Y: yy

        c: change,修改
            结合光标跳转字符使用,修改跳转范围内的字符
                w, b, e, 
                $, 0, ^
            先删除,再转换为输入模式
            cc, C: 删除光标所在处的整行而后转换为输入
            #c

    撤消编辑:
        u: undo, 
        #u: 撤消最近的#次操作

    撤消此前的撤消操作:
        Ctrl+r

    重复前一条命令:
        .

    vimtutor

末行模式:
    行间跳转
        #
            $: 最后一行

    内容定界:
        startpos,endpos
            #: 第#行
            .: 当前行
            $: 最后一行
            %: 全文,相当于1,$
            10,$-1

        c, d, y等命令可以直接附加在地址范围后使用

        w /path/to/somefile: 将选定范围内的内容保存至某文件中
        r /path/from/somefile: 将指定的文件中的内容读取到指定位置

        s/查找模式/要替换成的内容/gi
            查找模式:可以使用正则表达式
            要替换成的内容:不能使用模式,仅能使用引用

        s@@@gi

            g: global, 全行替换
            i: 不区分字符大小写

            引用模式匹配到的所有内容,可以使用&符号

        练习:复制/etc/rc.d/init.d/functions至/tmp目录
            替换/tmp/functions文件中的/etc/sysconfig/init为/var/log
            %s/\/etc\/sysconfig\/init/\/var\/log/gi
            %s@/etc/sysconfig/init@/var/log@gi


        练习:
            1、复制/etc/grub.conf至/tmp目录,删除/tmp/grub.conf文件中的行首的空白字符;
            %s@^[[:space:]]\{1,\}@@g

            2、复制/etc/rc.d/rc.sysinit至/tmp目录,将/tmp/rc.sysinit文件中的以至少一个空白字符开头的行的行首加#号;
            %s@^\([[:space:]]\{1,\}.*\)@#\1@

            %s@^[[:space:]]\{1,\}.*@#&@

            3、删除/tmp/rc.sysinit文件中以#开头,且后面跟了至少一个空白字符的行的行首的#号和空白字符;
            %s@^#[[:space:]]\{1,\}@@

            4、为/tmp/grub.conf文件中前三行的行首加#号;
            1,3s@^@#@

            5、将/etc/yum.repos.d/CentOS-Media.repo文件中的所有enable=0和gpgcheck=0两行最后的0改为1;
            %s@enable=0@enable=1@
            %s@\(enable\|gpgcheck\)=0@\1=1@g

vim可视化模式:
    v:光标走过的字符
    V:光标走过的行

文本查找:
    用法同less命令
        /pattern
        ?pattern

        n
        N

翻屏:
    Ctrl+f: 向文件尾部翻一屏
    Ctrl+b: 向文件首部翻一屏
    Ctrl+d: 
    Ctrl+u:
    j:
    k:


多文件模式:
    :next
    :previous
    :last
    :first

    :wqall

多窗口模式:
    多文件:
        vim 
            -o: 水平分割
            -O: 垂直分割

            Ctrl+w, Arrow
    单文件:
        Ctrl+w, s: 水平分割
        Ctrl+w, v: 垂直分割

窗口属性定义:
    :set nu
        显示行号

    :set nonu

    :set ai
    :set noai

    :set ic
    :set noic

    :set sm
    :set nosm

    语法高亮:
        :syntax on|off

    搜索高亮:
        :set hlsearch
        :set nohlsearch



    配置文件:
        全局:/etc/vimrc
        用户:~/.vimrc

vim回顾:
总结:编辑、输入、末行、可视(v, V)

编辑-->输入
    i, I
    a, A
    o, O
    c, C

跳转:
    h,j,k,l
    w,b,e
    ^, $, 0
    G, #G
    ), (
    }, {

d, y, c

u, Ctrl+r

多编辑器同时编辑同一个文件:

-o, -O; 

vim +# FILE

vim, vi

bash编程:
bash进程:解释器
type

shell脚本:
第一行,顶格:
    shebang
    #!/bin/bash
    #!/usr/bin/python

    其它的以#开头的行均为注释,会被解释器忽略;

练习:
    创建一个组newgroup,id号8008;
    创建一个用户,名字为mageedu, id号为3306,附加组为newgroup
    创建目录/tmp/hellobash
    复制/etc/rc.d/init.d/functions至/tmp/hellobash目录中

过程式编程语言:
    顺序执行
    选择执行:测试条件,可能会多个测试条件,某条件满足时,则执行对应的分支
    循环执行:将同一段代码反复执行多次;因此,循环必须有退出条件;否则,则陷入死循环;

bash 
    -n: 语法测试
    -x: 模拟单步执行

变量类别:
    本地变量
    环境变量
        export:导出
    局部变量
    位置变量
        $1, ..., $n, ${10}
            练习:写一个脚本,能接受一个参数作为用户名,此脚本可创建此用户,并且其密码同用户名;
            shift [n]
    特殊变量:
        $?
        $#: 传递给脚本参数的个数
        $*
        $@:引用传递给脚本的所有参数

bash的循环语句:
    for:遍历有限的元素列表,
    while:
    until:

    for语句的格式:
        for VAR_NAME in LIST
        do
            循环体
        done

        LIST:列表,中间包括一个或多个元素

        退出条件:遍历结束

        练习:创建10个用户,user301, user310
            列表:user301, user310
            列表:301, 310

            生成数值列表:
                {start..end}
                    例如:{1..100}
                seq
                    命令引用 

            for userNo in {301..310}
            for userNo in $(seq 301 310); do
                useradd user${userNo}
            done

        练习:创建目录/tmp/dir-当前日期时间;例如/tmp/dir-20140707-155503
            在此目录中创建10个空文件,分别为file1-file10;

        练习:写一个脚本
        1、创建用户tuser1-tuser9; 
        2、创建目录/tmp/dir-当前日期时间;
        3、在/tmp/dir-当前日期时间 目录中创建9个空文件file101-file109
        4、将file101的属主改为tuser1,依次类推,一直将file109的属主改为tuser9;



        练习:写一个脚本
        1、脚本可以接受一个以上的文件路径作为参数;
        2、显示每个文件所拥的行数;

        3、显示本次共对多少个文件执行了行数统计;
        !/bin/bash
        #
        for file in $*; do
            lines=`wc -l $file | cut -d' ' -f1`
            echo "$file has $lines lines."
        done

        echo "$# files."



        练习:写一个脚本
        1、显示/etc/passwd文件中位于文件的第偶数行的用户名;并显示共有多少个这样的用户;
            #!/bin/bash
            #
            totalUsers=`wc -l /etc/passwd | cut -d' ' -f1`

            for i in `seq 2 2 $totalUsers`; do
                userName=`head -n $i /etc/passwd | tail -1 | cut -d: -f1`
                echo $userName >> /tmp/passwd.tmp
                echo $userName
            done

            users=`wc -l /tmp/passwd.tmp | cut -d' ' -f1`
            echo "Total users: $users."             



    生成列表的方式:
        1、手动给个列表:
            for i in 1 2 3 4 5;
        2、数值列表:
            {start..end}
            `seq [start [increment]] end`
        3、$*, $@
        4、命令生成列表

bash如何实现算术运算:
    变量:弱类型

    如何定义整型变量:
        let VAR_NAME=INTEGER_VALUE
            例如:let a=3

        declare -i VAR_NAME=INTEGER_VALUE
            例如:declare -i a=3

    注意:即使没有定义为整型变量,字符型的数字依然可以参与算术运算;bash会执行变量类型的隐式类型转换;

    实现算术运算的方式:
        let VAR_NAME=ARITHMATIC_EXPRESSION
        VAR_NAME=$[ARITHMATIC_EXRESSION]
        VAR_NAME=$((EXPRESSION))
        VAR_NAME=$(expr $num1 + $num2)

    算术运算符:
        +
        -
        *
        /
        %:取模,取余数
            5%2=1, 
        **: 2**2

    练习:计算100以内所有正整数之和
        #!/bin/bash
        #
        declare -i sum=0

        for i in {1..100}; do
          sum=$[$sum+$i]
        done

        echo $sum

    练习:分别计算100以内所有偶数之和和奇数之和;
        #!/bin/bash
        #
        declare -i evensum=0
        declare -i oddsum=0

        for i in `seq 1 2 100`; do
          oddsum=$[$oddsum+$i]
        done

        for j in `seq 2 2 100`; do
          evensum=$[$evensum+$j]
        done

        echo "evensum: $evensum, oddsum: $oddsum."


    练习:计算当前系统上所有用户的ID之和;

        declare -i idsum=0

        for i in `cut -d: -f3 /etc/passwd`; do
            let idsum+=$i
        done

        echo $idsum

    练习:写一个脚本
        1、脚本可以接受一个以上的文件路径作为参数;
        2、显示每个文件所拥有的行数;
        3、显示本次共对多少个文件执行了行数统计;
        4、显示所有文件的总行数;

            #!/bin/bash
            #
            declare -i totalLines=0
            declare -i noFiles=0

            for file in $*; do
                curFileLines=`wc -l $file | cut -d' ' -f1`
                echo "$file has $curFileLines."
                let noFiles++
                let totalLines+=$curFileLines
            done

            echo "Total Files: $noFiles."
            echo "Total Lines: $totalLines."


    练习:新建10个用户tuser401-tuser410,并求他们的ID之和;
        #!/bin/bash
        #
        declare -i idsum=0

        for i in {401..410}; do
            useradd tuser$i
            userID=`id -u tuser$i`
            let idsum+=$userID
        done

        echo "ID sum: $idsum."          

    练习:写一个脚本
        1、创建用户tuser501-tuser510; 
        2、创建目录/tmp/dir-当前日期时间;
        3、在/tmp/dir-当前日期时间 目录中创建9个空文件file101-file110
        4、将file101的属主改为tuser501,依次类推,一直将file110的属主改为tuser510;   


    练习:写一个脚本
        分别统计/etc/rc.d/rc.sysinit、/etc/rc.d/init.d/functions和/etc/inittab文件中以#开头的行的行数和空白行数;
        
            #!/bin/bash

            for file in /etc/rc.d/rc.sysinit /etc/rc.d/init.d/functions /etc/inittab; do
                echo "The lines contain #  in $file is `grep -E "^#" $file | wc -l`." 
                echo "The space lines in $file is `grep -E "^[[:space:]]*$" $file | wc -l`." 
            done


    练习:写一个脚本
        显示当前系统上所有默认shell为bash的用户的用户名、UID及其所有此类用户的UID之和;
            #!/bin/bash
            #
            grep "/bin/bash$" /etc/passwd | cut -d: -f1,3

            declare -i sum=0
            for userID in `grep "/bin/bash$" /etc/passwd | cut -d: -f3`; do
                let sum+=$userID
            done

            echo "$sum"


bash弱类型:
    变量=值
        任何无需事先声明,可直接使用
        值默认都是字符型
        a=abc, b=3
        a=3
        赋值:
            a=4
        增强型赋值:
            +=, -=, *=, /=, %=
            a=$[$a+1] 相当于 let a+=1

            自加:var++, var--, ++var, --var
        export PATH=$PATH:/usr/local/apache/bin

        unset: 撤消 

    算术运算:bash会对数字执行隐式的类型转换
        let VAR_NAME=Integer_Value
        declare -i Var_Name=Integer_Value

        操作符:
            +, -, *, /, %, **

            双目运算符:需要至少两个操作数

    bash的算术运算的方式:
        let Var_Name=EXPRESSION
        $[EXPRESSION]
        $((EXPRESSION))
        命令:expr ARG1 OP ARG2

    for循环:
        新建10个用户:tuser601-tuser610
            useradd $userName

        for Var in LIST; do

        for userName in tuser601 tuser602 tuser603; do
            useradd $userName
        done

        for i in {601..610}; do
            useradd tuser$i
        done

        遍历LIST元素,遍历结束,循环退出;

    bash中的字串连接:
        变量引用后方跟直接字串时,变量名要加{}

        求100以内所有正整数的和:
            declare -i sum=0

            sum+=1, 0+1
            sum+=2, 0+1+2
            sum+=3
            sum+=4
            ...
            sum+=100

        declare -i sum=0
        for i in {1..100}; do
            let sum+=$i
        done

        echo $sum

练习:写一个脚本,显示当前系统上有附加组的用户的用户名;并统计共有多少个此类用户;
for userName in `cut -d: -f1 /etc/passwd`; do
    id $userName | 

    # egrep '[^:]$' /etc/group | cut -d: -f4 | sort -u | egrep -o '[[:alnum:]]*' | sort -u

写一个脚本,创建十个用户tuser401, tuser410

实现某种操作:总是 测试 前提是否满足

/tmp/test
    10

逻辑运算:
    布尔运算:真,假

    与、或、非、异或

    与运算:
        真,假:
            真 && 真 = 真
            真 && 假 = 假
            假 && 真 = 假
            假 && 假 = 假

    或运算:
        真,假
            真 || 真 = 真
            真 || 假 = 真
            假 || 真 = 真
            假 || 假 = 假

    非运算:
        真,假

    异或运算:

命令都有其状态返回值:
    成功:0,真
    失败:1-255, 假

bash条件测试:
    命令执行成功与否即为条件测试
        test EXPR
        [ EXPR ]
        [[ EXPR ]]

    比较运算:
        >, <, >=, <=, ==, !=

    测试类型:根据比较时的操作数的类型
        整型测试:整数比较
        字符测试:字符串比较
        文件测试:判断文件的存在性及属性等

        注意:比较运算通常只在同一种类型间进行

        整型测试:
            -gt: 例如 [ $num1 -gt $num2 ]
            -lt: 
            -ge: 
            -le:
            -eq:
            -ne:

        字符串测试:
            双目
                >: [[ "$str1" > "$str2" ]]
                <:
                >=
                <=
                ==
                !=

            单目:
                -n String: 是否不空,不空则为真,空则为假
                -z String: 是否为空,空则为真,不空则假

过程式编程:
    顺序
    选择
    循环:for

选择:if和case

if: 三种使用格式
    单分支的if语句:
        if 测试条件; then
             选择分支
        fi
            表示条件测试状态返回值为值,则执行选择分支;

            if ! id $username &> /dev/null; then
                useradd $username
            fi

        练习:写一个脚本,接受一个参数,这个参数是用户名;如果此用户存在,则显示其ID号;

    双分支的if语句:
        if 测试条件; then
            选择分支1
        else
            选择分支2
        fi

        两个分支仅执行其中之一。

        练习:通过命令行传递两个整数参数给脚本,脚本可以返回其大者。

        练习:通过命令行传递任意个整数给脚本,脚本可以返回其大者。

        练习:通过命令行给定一个文件路径,而后判断:
            如果此文件中存在空白行,则显示其空白行的总数;
            否则,则显示无空白行;

            if grep "^[[:space]]*$" $1 &> /dev/null; then
                echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."
            else
                echo "No blank lines"
            fi

            注意:如果把命令执行成功与否当作条件,则if语句后必须只跟命令本身,而不能引用。

            if [ $(grep "^[[:space:]]*$" $1 | wc -l) -lt 1 ]

    多分支的if语句:
        if 条件1; then
            分支1
        elif 条件2; then
            分支2
        elif 条件3; then
            分支3
        ...
        else
            分支n
        fi

        练习:传递一个参数给脚本:   
            如果参数为quit,则显示说你要退出;
            如果参数为yes,则显示说你要继续
            其它任意参数,则说无法识别;

        练习:传递一个用户名给脚本:
            如果此用户的id号为0,则显示说这是管理员
            如果此用户的id号大于等于500,则显示说这是普通用户
            否则,则说这是系统用户;

            #!/bin/bash
            #
            if [ $# -lt 1 ]; then
                echo "Usage: `basename $0` username"
                exit 1
            fi

            if ! id -u $1 &> /dev/null; then
                echo "Usage: `basename $0` username"
                echo "No this user $1."
                exit 2
            fi

            if [ $(id -u $1) -eq 0 ]; then
                echo "Admin"
            elif [ $(id -u $1) -ge 500 ]; then
                echo "Common user."
            else
                echo "System user."
            fi

    if 测试条件; then
        测试条件:在bash中是命令 (test EXPR, [ EXPR ] ) 或由 [[ EXPR ]]
        if 命令;
            在bash运行至if时,其后的命令会被执行,其状态结果则作为判断标准:
                0:表示真
                1-255:表示假

            如果条件包含比较之意,则必须使用

自定义shell进程的状态返回值:
exit [n]

回顾:
条件测试:
整型测试:数值间的大小比较
-gt, -lt, -eq, -ne, -ge, -le
字符串测试:字符串大小比较
>, <, ==, !=, =~, -n, -z
文件测试

例如:如果当前主机的主机名为localhost,则将其修改为www.magedu.com

    比较时,
    if [ `hostname` == 'localhost' ]; then
        hostname www.magedu.com
    fi

例如:如果当前主机的主机名为空,则将其修改为用户通过命令行参数传递过来的用户名
    hostName=`hostname`

    if [ -z "$hostName" ]; then
        hostname $1
    fi

组合条件测试:在多个条件间实现逻辑运算
    与:[ condition1 -a condition2 ]
        condition1 && condition2
    或:[ condition1 -o condition2 ]
        condition1 || condition2
    非:[ -not condition ]
        ! condition

    例如:如果当前主机的主机名为空,或者为"localhost",则将其修改为www.magedu.com
        #!/bin/bash
        #
        hostName=`hostname`

        if [ -z "$hostName" -o "$hostName" == 'localhost' ]; then
            hostname www.magedu.com
        fi

    如果某用户存在,则显示id号:
        if id $userName &> /dev/null; then
            id -u $userName
        fi

    例如:如果某用户存在,且answer变量的值为“yes",则显示用户的ID号;否则,说用户选择了退出;
        id $userName
        retVal=$?

        if [ $retval -eq 0 -a "$answer" == 'yes' ]; then

        上述方式改为:

        if id $userName &> /dev/null && [ "$answer" =='yes' ]; then

    例如:如果answer不为"quit",也不为"q",则说用户选择了继续;

    例如:如果answer不为quit或q,则说明用户选择了继续;

    德 摩根定律:
        
练习:给定一个用户,如果其shell为/bin/bash且其ID号大于等于500,则说这是一个可登录普通用户;否则,则显示其为非登录用户或管理员。

    #!/bin/bash
    #
    if ! id $1 &> /dev/null; then
        echo "No this user."
        exit 3
    fi

    userShell=$(grep "^$1\>" /etc/passwd | cut -d: -f7)
    userID=$(id -u $1)

    if [ "$userShell" == '/bin/bash' -a $userID -ge 500 ]; then
        echo "Login user."
    else
        echo "not login user."
    fi      

练习:写一个脚本
    如果某用户不存在,就添加之;
        #!/bin/bash
        #
        if ! id $1 &> /dev/null; then
            useradd $1
        fi      

练习:写一脚本
    1、添加10个用户:tuser501-tuser510
        如果用户不存在,才添加;如果存在,则显示已经有此用户
    2、显示一共添加了多少个用户;
        #!/bin/bash
        #
        declare -i count=0

        for i in {501..510}; do
            if id tuser$i &> /dev/null; then
                echo "tuser$i exists."
            else
                useradd tuser$i
                let count++
            fi
        done

        echo "Total add $count users."


练习:写一脚本
    1、添加10个用户:tuser601-tuser610
        如果用户不存在,才添加,并以绿色显示添加成功;如果存在,则以红色显示已经有此用户;
    2、显示一共添加了多少个用户;
        #!/bin/bash
        #
        declare -i count=0

        for i in {501..510}; do
            if id tuser$i &> /dev/null; then
                echo -e "\033[31mtuser$i\033[0m exists."
            else
                useradd tuser$i
                echo -e "add user \033[32mtuser$i\033[0m successfully."
                let count++
            fi
        done

        echo "Total add $count users."      

练习:写一个脚本
    传递用户名给脚本
    1、判断此用户的shell是否为/bin/bash,如果是,则显示此用户为basher
    2、否则,则显示此用户为非basher

        #!/bin/bash
        #
        userShell=`grep "^$1\>" /etc/passwd | cut -d: -f7`

        if [ "$userShell" == '/bin/bash' ]; then
            echo "basher"
        else
            echo "not basher"
        fi      

在剩下的三月里,你愿意与学习结为伴侣,无论贫穷还是富贵,无论电脑还是手机,无论多困或者多累,无论想吃还是想睡,都要把学习放在第一位,以不落后为目标,同甘共苦同舟共济永不言弃,爱惜她尊重她理解她保护她,你愿意这样做么?
Yes, I do.

bash条件测试之文件测试:

   -a file
          True if file exists.
   -b file
          True if file exists and is a block special file.
   -c file
          True if file exists and is a character special file.
   -d file
          True if file exists and is a directory.
   -e file
          True if file exists.
   -f file
          True if file exists and is a regular file.
   -g file
          True if file exists and is set-group-id.
   -h file
          True if file exists and is a symbolic link.
   -k file
          True if file exists and its ''sticky'' bit is set.
   -p file
          True if file exists and is a named pipe (FIFO).
   -r file
          True if file exists and is readable.
   -s file
          True if file exists and has a size greater than zero.
   -t fd  True if file descriptor fd is open and refers to a terminal.
   -u file
          True if file exists and its set-user-id bit is set.
   -w file
          True if file exists and is writable.
   -x file
          True if file exists and is executable.
   -O file
          True if file exists and is owned by the effective user id.
   -G file
          True if file exists and is owned by the effective group id.

   -L file
          True if file exists and is a symbolic link.
   -S file
          True if file exists and is a socket.
   -N file
          True if file exists and has been modified since it was last read.
   file1 -nt file2
          True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.
   file1 -ot file2
          True if file1 is older than file2, or if file2 exists and file1 does not.
   file1 -ef file2
          True if file1 and file2 refer to the same device and inode numbers.
   -o optname
          True  if  shell  option  optname  is  enabled.  See the list of options under the description of the -o option to the set builtin
          below.


      -a FILE
      -e FILE: 存在则为真;否则则为假;

      -f FILE: 存在并且为普通文件,则为真;否则为假;
      -d FILE: 存在并且为目录文件,则为真;否则为假;
      -L/-h FILE: 存在并且为符号链接文件,则为真;否则为假;
      -b: 块设备
      -c: 字符设备
      -S: 套接字文件
      -p: 命名管道

      -s FILE: 存在并且为非空文件则为值,否则为假;

      -r FILE
      -w FILE
      -x FILE

      file1 -nt file2: file1的mtime新于file2则为真,否则为假;
      file1 -ot file2:file1的mtime旧于file2则为真,否则为假;

例如:如果wget命令对应的可执行文件存在且可执行,则使用它下载http://172.16.0.1/centos6.5.repo至当前目录中;

    #!/bin/bash
    #
    downURL='http://172.16.0.1/centos6.5.repo'
    downloader=`which wget`

    if [ -x $downloader ]; then
        $downloader $downURL
    fi

练习:给定一个文件路径
    1、判断此文件是否存在;不存在,则说明文件不存,并直接结束脚本;
    2、如果文件是否普通文件,则显示为“regular file”;
       如果文件是目录,则显示为“directory”;
       如果文件是链接文件,则显示为“Symbolic file";
       否则,则显示为“unknown type.”

        #!/bin/bash
        #
        if [ ! -e $1 ]; then
            echo "file not exist."
            exit 8
        fi

        if [ -L $1 ]; then
            echo "Symbolic file"
        elif [ -d $1 ]; then
            echo "Directory"
        elif [ -f $1 ]; then
            echo "regular file."
        else
            echo "unknown."
        fi

练习:写一个脚本,完成如下任务:
    1、分别复制/var/log下的文件至/tmp/logs/目录中;
    2、复制目录时,才使用cp -r
    3、复制文件时,使用cp
    4、复制链接文件,使用cp -d
    5、余下的类型,使用cp -a



写一个脚本,完成如下任务,其使用形式如下所示:
    script.sh {start|stop|restart|status}
其中:
    如果参数为空,则显示帮助信息,并退出脚本;
    如果参数为start,则创建空文件/var/lock/subsys/script,并显示“starting script successfully.”
    如果参数为stop,则删除文件/var/lock/subsys/script,并显示“Stop script successfully.”
    如果参数为restart,则删除文件/var/locksubsys/script并重新创建,而后显示“Restarting script successfully.”
    如果参数为status,那么:
        如果文件/var/lock/subsys/script存在,则显示“Script is running...”,否则,则显示“Script is stopped.”

    说明:script.sh是脚本文件名,在创建时,其名称可以自己随意定义,但如果其名称发生变量,上/var/lock/sussys/下的文件名也要随之而变;

bash编程之交互编程

read 
    -p "prompt"
    -t timeout

例如:输入用户名,可返回其shell
    #!/bin/bash
    #
    read -p "Plz input a username: " userName

    if id $userName &> /dev/null; then
        echo "The shell of $userName is `grep "^$userName\>" /etc/passwd | cut -d: -f7`."
    else
        echo "No such user. stupid."
    fi

例子:显示一个如下菜单给用户:
    cpu) show cpu infomation
    mem) show memory infomation
    *) quit

    1、如果用户选择了cpu,则显示/proc/cpuinfo文件的内容;
    2、如果用户选择了mem,则显示/proc/meminfo文件的内容;
    3、退出

        #!/bin/bash
        #
        echo "---------menu----------"
        echo "cpu) show cpu infomation"
        echo "mem) show memory infomation"
        echo "*) quit"
        echo "-------menu------------"

        read -p "Plz give your choice: " choice

        if [ "$choice" == 'cpu' ]; then
            cat /proc/cpuinfo
        elif [ "$choice" == 'mem' ]; then
            cat /proc/meminfo
        else
            echo "Quit"
            exit 3
        fi



        #!/bin/bash
        #
        cat << EOF
        -------menu------------
        cpu) show cpu infomation
        mem) show memory infomation
        *) quit
        -------menu------------
        EOF

        read -p "Plz give your choice: " choice

        if [ "$choice" == 'cpu' ]; then
            cat /proc/cpuinfo
        elif [ "$choice" == 'mem' ]; then
            cat /proc/meminfo
        else
            echo "Quit"
            exit 3
        fi

字串测试中的模式匹配
[[ "$var" =~ PATTERN ]]

例如:让用户给定一个用户名,判断其是否拥有可登录shell;
    /bin/sh, /bin/bash, /bin/zsh, /bin/tcsh, /sbin/nologin, /sbin/shutdown


    #!/bin/bash
    #
    read -p "Plz input a username: " userName
    userInfo=`grep "^$userName\>" /etc/passwd`

    if [[ "$userInfo" =~ /bin/.*sh$ ]]; then
        echo "can login"
    else
        echo "cannot login"
    fi

练习:写一个脚本,完成如下功能
    使用格式:
        script.sh  /path/to/somefile

    1、可接受一个文件路径参数:
        如果此文件不存在,则创建之,则自动为其生成前n行类似如下:
            #!/bin/bash
            # description:
            # version:
            # date:
            # author: mageedu
            # license: GPL
        而后使用vim打开此文件,并让光标处在最后一行的行首
        如果文件存在、且是bash脚本,则使用vim打开之,光标自动处行最后一行的行首;
        否则,退出;

        如果正常编辑保存,
            判断,如果文件没有执行权限,则添加之;

            判断,其是否有语法错误,如果有,提示;

文件查找:根据文件的各种属性去找到相对应文件

文本搜索:grep, egrep, fgrep

文件查找:locate, find
    实时查找:遍历所有文件进行条件匹配
    非实时查找:根据索引查找

    locate: 非实时查找
        依赖于索引,而索引构建相当占用资源;索引的创建是在系统空闲时由系统自动进行(每天任务);手动进行使用updatedb命令;
            查找速度快
            非精准查找
        模糊查找

    find: 实时查找
        精准查找
        精确查找

        速度慢

find [option]... [查找路径] [查找条件] [处理动作]   
    查找路径:默认为当前目录
    查找条件:默认为指定路径下的所有文件
    处理动作:默认为显示至屏幕

查找条件:
    -name "文件名称":支持使用globbing字符
        *: 
        ?:
        []:
        [^]:
    -iname "文件名称":查找时忽略字符大小写

    -user USERNAME: 根据文件的属主查找
    -group GRPNAME: 根据文件的属组查找

    -uid UID
    -gid GID

    -nouser: 查找没有属主的文件
    -nogroup: 查找没有属组的文件

    组合条件查找:
        与:-a, 同时满足
        或:-o, 满足一个即可
        非:-not, !,条件取反

        -not A -a -not B = -not (A -o B)
        -not A -o -not B = -not (A -a B)

            例子:-not \( -iname "*r* -o -user gentoo \)

    -type TYPE: 根据文件类型查找
        f: 普通文件
        d: 目录文件
        l: 符号链接
        b: 块设备
        c: 字符设备
        s: 套接字文件
        p: 命名管道

    -size [+|-]#UNIT
        常用单位: k, M, G

        #UNIT: #-1 < x <= #
        -#UNIT: x <= #-1
        +#UNIT: x > #

    根据时间戳查找:
        以“天”为单位
            -atime [+|-]#
                +#:x >= #+1
                -#:x < #
                #: # <= x < #+1 
            -mtime
            -ctime

        以“分钟”为单位 
            -amin
            -mmin
            -cmin

    根据权限查找:
        -perm [+|-]MODE
            MODE: 与MODE精确匹配
                find ./ -perm 644
            +MODE: 任何一类用户的权限只要能包含对其指定的任何一位权限即可;以属主为例,
                find ./ -perm +222  
            -MODE:每类用户指定的检查权限都匹配:   
                为三类用户所有指定的检查权限都能够被包含
                find ./ -perm -222

处理动作:
    -print: 默认处理动作,显示
    -ls:类似于ls -l
    -exec COMMAND {} \;
    -ok COMMAND {} \;

    find: 一次性查找符合条件的所有文件,并一同传递给给-exec或-ok后面指定的命令;但,有些命令不能接受过长的参数;此时使用另一种方式

        find | xargs COMMAND

总结:find [查找路径] [查找条件] [处理动作]
    查找条件:
        -name, -iname, -user, -group, -uid, -gid, -nouser, -nogroup, -type, -size, -atime, -mtime, -ctime, -amin, -mmin, -cmin, -perm
        组合:-a, -o, -not
    处理动作:

练习:
1、查找/var/目录属主为root且属组为mail的所有文件;

find /var -user root -a -group mail

2、查找/usr目录下不属于root、bin或hadoop的所用文件;
find /usr -not -user root -a -not -user bin -a -not -user hadoop
find /usr -not (-user root -o -user bin -o -user hadoop)

3、查找/etc/目录下最近一周内其内容修改过的,且不属于root且不属于hadoop的文件;
find /etc -mtime -7 -a -not (-user root -o -user hadoop)

4、查找当前系统上没有属主或属组,且最近1个月内曾被访问过的文件;
find / (-nouser -o -nogroup) -a -atime -30

5、查找/etc/目录下大于1M且类型为普通文件的所有文件;
find /etc -size +1M -type f

6、查找/etc/目录所有用户都没有写权限的文件;
find /etc/ -not -perm +222

7、查找/etc/目录下至少有一类用户没有写权限;
find /etc/ -not -perm -222

8、查找/etc/init.d/目录下,所有用户都有执行权限且其它用户有写权限的文件;
find /etc/init.d/ -perm -113

find补充材料(摘自互联网):

find与xargs
在使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现 溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。

find命令把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。

在有些系统中,使用-exec选项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高;

而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。

特殊权限:

mode: 
    ls -l

安全上下文
    1、进程以某用户身份运行;进程是发起此进程的用户的代理,其用户身份进程发起者;
    2、权限匹配模型:
        (1) 进程的属主,是否与被访问的文件属主相同;
        (2) 进程的属主所属于的组当中,是否有一个与被访问的文件的属组相同;
        (3) 以other的权限进行访问;

suid: Set UID
    前提:此类文件为有可执行权限的命令
    任何用户运行此命令为一个进程时,此进程的有效身份不是发起者,而是命令文件自身的属主;

    chmod u+s FILE...
        使用ls -l查看时,此s可能显示为大写或小写两种形式之一;
            属主原有执行权限时,显示为小写;

sgid: Set GID
    前提:
        常用方法:如果将目录的属组设置SGID权限之后,所有用户在此目录创建文件的属组不再是用户的基本组,而是目录的属组

    chmod g+s FILE...

有那么一个目录:
    指定的用户都能够在其中创建文件,也能删除自己的文件;但不能删除别人的文件;

sticky: 沾滞位

    chmod o+t FILE...

suidsgidsticky
000: 
001: 
010
011
100
101
110
111

chmod 7755 

练习:
    1、让普通用户使用/tmp/cat能查看管理员才有权限访问的文件;
    2、新建目录/project/test,让普通用户hadoop和openstack对此目录都能创建文件,且创建的文件的属组为此目录的属组,而非用户自身的属组,此外还要求,每个用户不能删除其它人的文件;

回顾:
find 和 特殊权限

    find: 
        1、-type b
        2、-size +20M -a -atime +7

    suid, sgid, sticky

任务计划和facl:

一次性任务执行:at, batch
周期性任务执行:crontab

一次性任务执行:
    at TIME
    at> ls /etc
    at> ls -l /var
    at> wc -l /etc/fstab
    at>
    Ctrl+d:提交任务

    TIME: 
        模糊时间:
            now+#UNIT
            noon
            midnight
            teatime
            tomorrow
            hh:mm

        at有作业队列:
            使用单个字母表示

    atq: 查看作业队列中的待执行任务
        at -l

    任务作业执行完成后:结果会通过邮件通知给作业提交者

        CentOS: 默认会安装并启动邮件服务,仅服务于本地系统;
            # mail

    at -d = atrm

    batch: 功能同at, 但无须为其指定时间,其会选择系统资源较空闲时执行指定的作业



周期性任务执行:cron, vixie-cron, cronie
    crond: cron daemon, cron守护进程,一直工作于后台

    # service crond status
    crond (pid  1718) is running...

    如果状态信息为“is stopped.”,则需要执行“service crond start; chkconfig crond on”;

    cron任务分两类:
        系统cron: 定义在/etc/crontab
        用户cron: 定义在/var/spool/cron目录中,每个用户都有一个与用户名同名的文件,其功能类似于/etc/crontab

    每行定义一个独立的任务:

    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    HOME=/
        
    # 环境变量

    # For details see man 4 crontabs

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
    # |  |  |  |  |
    # *  *  *  *  * user-name command to be executed

    注意:如果定义在cron中的任务是脚本,此脚本中的各命令查找时遵循的是cron的PATH环境变量定义;因此,在命令行中测试无问题的脚本,在cron中未必;
        解决方案:   
            命令使用绝对路径
            在脚本中开始自己定义一个专用PATH环境变量

    用户cron的每个作业由2部分组成
        时间
            分钟  小时  日   月   周几 
        命令

    时间表示法:
        1、每个时间位都应该使用其可用的有效取值范围内的值
            3 * * * * /bin/echo "howdy"
            17 3 * * * /bin/echo "howdy"
            7 6 5 * * /bin/echo "howdy"
            7 6 5 4 *

            1 9 * * 3 /bin/echo "howdy"
        2、某个时间位上的*表示对应时间位的所有有效取值;
        3、*/#: 在对应的时间位的有效取值上每#一次;
            */3 * * * * 
            0 */3 * * *
            */8 * * * *: ?
                0-59
                    0, 8, 16, 24, 32, 40, 48, 56, 
        4、某个时间位上的连续区间:-
            10-50/3 * * * *
        5、离散取值:,
            1 7,9,13 * * * 

    丢弃邮件通知:
        输出重定向:
            > /dev/null
            &> /dev/null
            > /dev/null 2>&1

    用户cron任务的定义方式:
        crontab 
            -l: 列出已经定义的所有任务
            -e: 打开编辑界面定义任务
            -r: 移除所有任务

            crontab -u USERNAME -e

    注意:如果在crontab的用户命令中使用%,得转义,使用\%的格式;不过,如果使用单引号引起来,也可不用转义;
        5 3 * * * /bin/touch /tmp/testfile-$(date +\%F-\%H-\%M-\%S)
        6 4 * * * /bin/touch /tmp/testfile-$(date +'%F-%H-%M-%S')

    练习:
        1、每4小时执行一次对/etc/目录的备份,备份至/backup目录中,保存的目录名为etc-2014071004;
        0 */4 * * * [ -d /backup ] || mkdir /backup; /bin/cp -a /etc /backup/etc-$(date +'%Y%m%d%H')

        2、每周3,5,7备份/var/log/messages文件至/backup/message_logs/目录中,保存的文件名为messages-2014071004;
        3 1 * * 3,5,7 

        3、每天每两小时取当前系统/proc/meminfo中的以S开头的信息保存至/stats/memory.txt中
        2 */2 * * * grep -i "^S" /proc/meminfo >> /stats/memory.txt 

        4、工作日的工作时间内,每小时执行一次'echo "howdy"'
        10 8-18 * * 1-5 echo "howdy"

    bash编程中:
        逻辑操作:
            &&: condition1 && condition2
            ||: condition1 || condition2

    如何实现秒级别的任务:
        每10秒钟:
            * * * * * for i in {1..5}; do echo "howdy"; sleep 10; done
            0
            10
            20
            30
            50
            0

    anacron: crontab的补充机制
        检查有没有过去一个有效周期未曾执行的任务,如果有,在开机后的指定时间点执行一次;

总结:
    任务计划:
        一次性:at, batch
        周期性:cron

    cron:
        PATH环境变量
        任务时间格式

facl: file acl
acl: access control list

chown: 普通用户能否改变文件的属主属组?
chmod: 普通用户是否有权限使用?

openstack用户,docker(读写)

通过facl机制,普通用户可以单独向某用户或某组设定对某文件访问权限;不通过修改属主或属组来实现的。

文件系统:
    ext: extended 
        ext2, ext3, ext4, 
        xfs

    lsattr, chattr
        i
        u

facl: 
    让普通用户透过文件的扩展属性,为其添加额外的用户访问授权机制而无须改变其属主、属组,也不用更改other的权限;

    getfacl
    setfacl {-m|-x} 目标:MODE FILE...
        -m u:USERNAME:MODE
        -m g:GROUPNAME:MODE

        -x u:USERNAME
        -x g:GROUPNAME

        -R: 递归

    启用facl之后权限应用模型:
        属主:
        用户级别的facl: 
        属组:
        组级别的facl:
        其它

bash编程之循环:
顺序
选择:if
循环:for

另一种循环:while 和 until
    for i in {1..100}; do

    done

    while适用于循环次数未知,或不便用for直接生成较大的列表时;

    while 测试条件; do
        循环体
    done

    如测试结果为“真”,则进入循环;退出条件为,测试条件为假;

        declare -i count=1
        while $count <= 1000; do
            循环体
            let count++
        done

    until 测试条件; do
        循环体
    done

    如果测试结果为“假”,则进入循环;退出条件为,测试条件为真;

    练习:求100以内所有正整数之和

        #!/bin/bash
        #
        declare -i count=1
        declare -i sum=0

        until [ $count -gt 100 ]; do
            let sum+=$count
            let count++
        done

        echo $sum


        #!/bin/bash
        #
        declare -i count=1
        declare -i sum=0

        while [ $count -le 100 ]; do
            let sum+=$count
            let count++
        done

        echo $sum

    练习:求100以内所有偶数之和;要求使用取模方法;

        #!/bin/bash
        #
        declare -i counter=1
        declare -i sum=0

        while [ $counter -le 100 ]; do
            if [ $[$counter%2] -eq 0 ]; then
                let sum+=$counter
            fi
            let counter++
        done

        echo $sum

        #!/bin/bash
        #
        declare -i counter=1
        declare -i sum=0

        while [ $counter -le 100 ]; do
            [ $[$counter%2] -eq 0 ] && let sum+=$counter
            let counter++
        done

        echo $sum

        请用until实现上述过程;

    练习:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;
          显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止;

          read -p "Plz enter a username: " userName

          while [ "$userName" != 'q' -a "$userName" != 'quit' ]; do
              if id $userName &> /dev/null; then
                  grep "^$userName\>" /etc/passwd | cut -d: -f3,7
              else
                  echo "No such user."
              fi

              read -p "Plz enter a username again: " userName
          done

        请用until实现上述过程;

回顾:facl, at, crontab, while, until

你可能感兴趣的:(杂)