• bash编程基础





    bash变量

    变量命名:
    1、不能使用程序中的关键字(保留字)
    2、只能使用数字、字母和下划线,且不能以数字开头
    3、要见名知义

    变量类型:
    数值型:精确数值(整数),近似数值(浮点型)
    字符型:char,string
    布尔型:true, false
    类型转换:显式转换,隐式转换

    按使用范围分类
    可赋值
    环境变量:对当前shell进程及其子shell有效,对其它的shell进程无效         
    定义:export VAR_NAME=VALUE
    导出:export VAR_NAME
    撤消变量:unset VAR_NAME
    只读变量:readonly VAR_NAME 
    本地变量:只对当前shell进程有效的变量,对其它shell进程无效,包当前shell进程的子进程
    VAR_NAME=VALUE
    局部变量:对shell脚本中某代码片断有效,通常用于函数本地
    local VAR_NAME=VALUE 
    不赋值
    位置变量:用来接受变量指定位置的参数
    $1,$2...,${10} 
    特殊变量:shell对一些参数做特殊处理,这些参数只能被引用而不能被赋值
    $#  传递到脚本的参数个数
    $@  与$*相同,但是使用时加引号,并在引号中返回每个参数
    $*  显示所有向脚本传递的参数   #与位置变量不同,此选项参数可超过9个
    $$  获取当前shell的进程号
    $!  执行上一个指令的进程号
    $?  获取执行的上一个指令的返回值              #0为执行成功,非零为执行失败
    $-  显示shell使用的当前选项,与set命令功能相同

    变量引用:${VAR_NAME}         
    "":弱引用,里面的变量会被替换
    '':强引用,里面的所有字符都是字面量,直接输出 

    查看变量
    set:查看当前shell进程中的所有变量
    export, printenv, env:查看当前shell进程中的所有环境变量 

    bash的配置文件
    profile类:为交互式登录的用户提供配置
    全局:/etc/profile、/etc/profile.d/*.sh
    用户:~/.bash_profile
    bashrc类:为非交互式的用户提供配置
    全局:/etc/bashrc
    用户:~/.bashrc
    功能:设定本地变量,定义命令别名


    编写与执行

    编写格式:
    shell脚本第一行必须顶格写,用shebang定义指定的解释器来解释该脚本。
    #!/bin/bash       #!即为shebang 
    其它的以#开头的行均为注释,会被解释器忽略,可用来注释脚本用途及版本,方便使用管理。

    执行方式:
    bash编程属于面向过程编程,执行方式如下:
    顺序执行:按命令先后顺寻依次执行
    选择执行:测试条件,可能会多个测试条件,某条件满足时,则执行对应的分支
    循环执行:将同一段代码反复执行多次,因此,循环必须有退出条件;否则,则陷入死循环

    bash执行选项:
    bash -n SHELLNAME  #语法测试,测试是否存在语法错误
    bash -x SHELLNAME  #模拟单步执行,显示每一步执行过程 

    算数运算与逻辑运算

    算数运算
    定义整型变量:
    let VAR_NAME=INTEGER_VALUE            #例如:let a=3
    declare -i VAR_NAME=INTEGER_VALUE     #declare -i a=3 

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

    算术运算符:
    +:加法
    -:减法
    *:乘法
    /:整除
    %:取余数
    **:乘幂 
    注意:即使没有定义为整型变量,字符型的数字依然可以参与算术运算,bash会执行变量类型的隐式类型转换。

    逻辑运算
    布尔运算:
    真,假
    与运算:
    真 && 真 = 真
        真 && 假 = 假
        假 && 真 = 假
        假 && 假 = 假
    或运算:
    真 || 真 = 真
        真 || 假 = 真
        假 || 真 = 真
        假 || 假 = 假
    非运算:
    !真=假
        !假=真 


    条件测试

    整型测试:整数比较
    例如 [ $num1 -gt $num2 ]
    -gt: 大于则为真
    -lt: 小于则为真
    -ge: 大于等于则为真
    -le: 小于等于则为真
    -eq: 等于则为真
    -ne: 不等于则为真 

    字符测试:字符串比较
    双目:
    例如[[ "$str1" > "$str2" ]]
    >: 大于则为真
    <: 小于则为真
    >=:大于等于则为真
    <=:小于等于则为真
    ==:等于则为真
    !=:不等于则为真 
    单目:
    -n String: 是否不空,不空则为真,空则为假
    -z String: 是否为空,空则为真,不空则假 

    文件测试:判断文件的存在性及属性等
    -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则为真,否则为假; 

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

    与:
    COMMAND1 && COMMAND2
    COMMAND1如果为假,则COMMAND2不执行
    或:
    COMMAND1 || COMMAND2
    COMMAND1如果为真,则COMMAND2不执行
    非:
    ! COMMAND 


    分支结构

    if之单分支
    语句结构:
    if 测试条件;then
       选择分支
    fi 
    表示条件测试状态返回值为值,则执行选择分支
    例:写一个脚本,接受一个参数,这个参数是用户名;如果此用户不存在,则创建该用户;
    if ! id $1 &> /dev/null;then
        useradd $1
    fi 

    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语句后必须只跟命令本身,而不能引用。

    补充:bash交互式编程read
    read [option] “prompt”
    -p:直接指定一个变量接受参数
    -t timaout:指定等待接受参数的时间
    -n:表示不换行 
    例:输入用户名,可返回其shell
    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 

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

    例:传递一个用户名给脚本:如果此用户的id号为0,则显示说这是管理员;如果此用户的id号大于等于500,则显示说这是普通用户;否则,则说这是系统用户。
    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 

    case语句:有多个测试条件时,case语句会使得语法结构更明晰
    语句结构:
    case 变量引用 in
    PATTERN1)
        分支1
    ;;
    PATTERN2)
        分支2
    ;;
    ...
    *)
        分支n
    ;;
    esac 
    PATTERN:类同于文件名通配机制,但支持使用|表示或者
    a|b: a或者b
    *:匹配任意长度的任意字符
    ?: 匹配任意单个字符
    []: 指定范围内的任意单个字符 

    例:写一个脚本,完成如下任务,其使用形式如下所示:
    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.”
    #!/bin/bash
    file='/var/lock/subsys/script'
    case $1 in
    start)
     if [ -f $file ];then
    echo "Script is running..."
     exit 3
     else
    touch $file
    [ $? -eq 0 ] && echo "Starting script successfully."
     fi
     ;;
    stop)
     if [ -f $file ];then
    rm -rf $file
    [ $? -eq 0 ] && echo "Stop script successfully."
     else
    echo "Script is stopped..."
    exit 4
     fi
     ;;
    restart)
     if [ -f $file ];then
    rm -rf $file
    [ $? -eq 0 ] && echo "Stop script successfully"
     else 
    echo "Script is stopped..."
    exit 5
     fi
    touch $file
    [ $? -eq 0 ] && echo "Starting script successfully"
     ;;
    status)
     if [ -f $file ];then
    echo "Script is running..."
     else
    echo "Script is stopped."
     fi
     ;;
    *)
    echo "`basename $0` {start|stop|restart|status}"
    exit 2
     ;;
    esac 


    循环

    for语句格式一
    语句结构:
    for 变量名 in 列表; do
        循环体
    done 
    列表:可包含一个或多个元素
    循环体:依赖于调用变量来实现其变化
    循环可嵌套
    退出条件:遍历元素列表结束

    例:求100以内所有正整数之和
    #!/bin/bash
    declare -i sum=0
    for i in {1..100}; do
        let sum+=$i
    done
    echo $sum 


    for语句格式二
    for ((初始条件;测试条件;修改表达式)); do
          循环体
    done 
    先用初始条件和测试条件做判断,如果符合测试条件则执行循环体,再修改表达式,否则直接跳出循环。

    例:求100以内所有正整数之和(for二实现)
    #!/bin/bash
    declare -i sum=0
    for ((counter=1;$counter <= 100; counter++)); do
        let sum+=$counter
    done
    echo $sum 


    while语句
    while适用于循环次数未知,或不便用for直接生成较大的列表时
    语句结构:
    while 测试条件; do
        循环体
    done 
    测试条件为真,进入循环;测试条件为假,退出循环

    例:求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 

    例:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止
    #!/bin/bash
    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 


    while特殊用法:遍历文本文件
    语句结构:
    while read 变量名; do
        循环体
    done < /path/to/somefile 
    变量名,每循环一次,记忆了文件中一行文本

    例:显示ID号为偶数,且ID号同GID的用户的用户名、ID和SHELL
    while read line; do
        userID=`echo $line | cut -d: -f3`
        groupID=`echo $line | cut -d: -f4`
        if [ $[$userID%2] -eq 0 -a $userID -eq $groupID ]; then
             echo $line | cut -d: -f1,3,7
        fi
    done < /etc/passwd 


    until语句
    语句结构:
    until 测试条件; do
          循环体
    done 
    测试条件为假,进入循环;测试条件为真,退出循环

    例:求100以内所有偶数之和,要求使用取模方法(until实现)
    #!/bin/bash
    declare -i counter=1
    declare -i sum=0
    until [ $counter -gt 100 ]; do
        if [ $[$counter%2] -eq 0 ]; then
             let sum+=$counter
        fi
        let counter++
    done
    echo $sum 

    例:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止(until实现)
    #!/bin/bash
    read -p "Plz enter a username: " userName
    until [ "$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 

    循环之循环控制和shift

    循环控制命令:
    break:提前退出循环
    break [N]: 退出N层循环;N省略时表示退出break语句所在的循环
    continue: 提前结束本轮循环,而直接进入下轮循环
    continue [N]:提前第N层的循环的本轮循环,而直接进入下轮循环

    死循环:
    #while体
    while true; do
          循环体
    done
    #until体
    until false; do
          循环体
    done 

    例:写一个脚本,判断给定的用户是否登录了当前系统
    (1) 如果登录了,则脚本终止;
    (2) 每5秒种,查看一次用户是否登录;
    #!/bin/bash
    while true; do
        who | grep "gentoo" &> /dev/null
        if [ $? -eq 0 ];then
    break
        fi
        sleep 5
    done
    echo "gentoo is logged." 

    shift:
    如果没有数字,只有shift 就是跳过一个参数获取下一个参数,如果加上数字,比如shift 2 ,跳过两个参数获取下一个参数。
    例:写一个脚本,使用形式如下所示    
    showifinfo.sh [-i INTERFACE|-a] [-v]
    要求:
    1、-i或-a不可同时使用,-i用于指定特定网卡接口,-a用于指定所有接口;
    显示接口的ip地址
    2、使用-v,则表示显示详细信息
    显示接口的ip地址、子网掩码、广播地址;
    3、默认表示仅使用-a选项;
    #!/bin/bash
    allinterface=0
    ifflag=0
    verbose=0
    interface=0
    if [ $# -eq 0 ];then
        ifconfig | grep "inet addr:" | awk '{print $2}'
    fi
    while [ $# -ge 1 ];do
      case $1 in
      -a)
        allinterface=1
        shift 1
      ;;
      -i)
        ifflag=1
        interface=$2
        shift 2
      ;;
      -v)
        verbose=1
        shift 1
      ;;
      *)
        echo "error option"
        exit 2
      ;;
      esac
    done
    if [ $allinterface -eq 1 ];then
      if [ $ifflag -eq 1 ];then
          echo "command not found"
          exit 5
      fi
      if [ $verbose -eq 1 ];then
          ifconfig | grep "inet addr:"
      else
          ifconfig | grep "inet addr:" | awk '{print $2}'
      fi
    fi
    if [ $ifflag -eq 1 ];then
      if [ $allinterface -eq 1 ];then
            echo "command not found"
            exit 5
      fi
      if [ $verbose -eq 1 ];then
          ifconfig $interface | grep "inet addr:"
      else
          ifconfig $interface | grep "inet addr:" | awk '{print $2}'
      fi
    fi 



    函数

    语法结构:
    function F_NAME {
            函数体
    }
    F_NAME() {
            函数体
    可调用:使用函数名,函数名出现的地方,会被自动替换为函数
    函数的返回值:
    函数的执行结果返回值:代码的输出
    函数中使用打印语句:echo, printf
    函数中调用的系统命令执行后返回的结果
    执行状态返回值:
    默认取决于函数体执行的最后一个命令状态结果
    自定义退出状态码:return [0-255]
    注意:函数体运行时,一旦遇到return语句,函数即返回;

    函数可以接受参数:
    在函数体中调用函数参数的方式同脚本中调用脚本参数的方式:位置参数
    $1, $2, ...
    $#, $*, $@

    例:写一个脚本,完成如下功能(使用函数):
    1、提示用户输入一个可执行命令;
    2、获取这个命令所依赖的所有库文件(使用ldd命令);
    3、复制命令至/mnt/sysroot/对应的目录中
    解释:假设,如果复制的是cat命令,其可执行程序的路径是/bin/cat,那么就要将/bin/cat复到/mnt/sysroot/bin/目录中,如果复制的是useradd命令,而useradd的可执行文件路径为/usr/sbin/useradd,那么就要将其复制到/mnt/sysroot/usr/sbin/目录中;
    4、复制各库文件至/mnt/sysroot/对应的目录中;
    #!/bin/bash
    target=/mnt/sysroot/
    [ -d $target ] || mkdir $target
    preCommand() {
        if which $1 &> /dev/null; then
    commandPath=`which --skip-alias $1`
    return 0
        else
    echo "No such command."
    return 1
        fi
    }
    commandCopy() {
        commandDir=`dirname $1`
        [ -d ${target}${commandDir} ] || mkdir -p ${target}${commandDir}
        [ -f ${target}${commandPath} ] || cp $1 ${target}${commandDir}
    }
    libCopy() {
        for lib in `ldd $1 | egrep -o "/[^[:space:]]+"`; do
        libDir=`dirname $lib`
        [ -d ${target}${libDir} ] || mkdir -p ${target}${libDir}
        [ -f ${target}${lib} ] || cp $lib ${target}${libDir}
        done
    read -p "Plz enter a command: " command
    until [ "$command" == 'quit' ]; do
      if preCommand $command &> /dev/null; then
        commandCopy $commandPath
        libCopy $commandPath
      fi
      read -p "Plz enter a command: " command
    done 


    信号捕捉

    trap命令用于在shell程序中捕捉到信号,之后可以有三种反应方式:
    (1)执行一段程序来处理这一信号
    (2)接受信号的默认操作
    (3)忽视这一信号

    trap对上面三种方式提供了三种基本形式:
    第一种形式的trap命令在shell接收到signal list清单中数值相同的信号时,将执行双引号中的命令串。
    trap 'commands' signal-list
    trap "commands" signal-list
    第二种形式的trap命令恢复信号的默认操作:trap signal-list
    第三种形式的trap命令允许忽视信号:trap " " signal-list
    trap 'COMMAND' SIGINT(表示关闭进程)

    例:写一个脚本,能够ping探测指定网络内的所有主机是否在线,当没有执行完时可接收ctrl+c命令退出。
    #!/bin/bash
    quitScript() {
         echo "Quit..."
    }    
    trap 'quitScript; exit 5' SIGINT
    cnetPing() {
        for i in {1..254}; do
            if ping -c 1 -W 1 $1.$i &> /dev/null; then
                echo "$1.$i is up."
             else
                echo "$1.$i is down."
            fi
            done
    }
    bnetPing() {
        for j in {0..255}; do
            cnetPing $1.$j 
        done
    }
    anetPing() {
        for m in {0..255}; do
            bnetPing $1.$m
        done
    }
    netType=`echo $1 | cut -d"." -f1`
    if [ $netType -ge 1 -a $netType -le 126 ]; then
        anetPing $netType
    elif [ $netType -ge 128 -a $netType -le 191 ]; then
        bnetPing $(echo $1 | cut -d'.' -f1,2)
    elif [ $netType -ge 192 -a $netType -le 223 ]; then
        cnetPing $(echo $1 | cut -d'.' -f1-3)
    else
        echo "Wrong"
        exit 2
    fi 


    数组

    数组:连续的多个独立内存空间,每个内存空间相当于一个变量
    数组元素:数组名+索引(从0开始编号)
    索引的表示方式:a[0], a[1]

    声明:
    声明普通数组:declare -a ARRAR_NAME
    声明关联数组:declare -A ARRAY_NAME
    支持稀疏格式:仅一维数组  

    数组元素的赋值:
    (1) 一次只赋值一个元素
    a[0]=$RANDOM
    ...
    (2) 一次赋值全部元素
    a=(red blue yellow green)
    (3) 指定索引进行赋值
    a=([0]=green [3]=red [2]=blue [6]=yellow)
    (4) 用户输入
    read -a ARRAY

    数组的访问:
    用索引访问:ARRAY[index]
    数组的长度:
    ${#ARRAY[*]}
    ${#ARRAY[@]}

    例:写一个脚本,生成10个随机数,保存至数组中;而后显示数组下标为偶数的元素
    #!/bin/bash
    for i in {0..9}; do
        rand[$i]=$RANDOM
        [ $[$i%2] -eq 0 ] && echo "$i:${rand[$i]}"
    done 

    从数组中挑选某元素:
    ${ARRAY[@]:offset:number}
    切片:
    offset: 偏移的元素个数
    number: 取出的元素的个数
    ${ARRAY[@]:offset}:取出偏移量后的所有元素
    ${ARRAY[@]}: 取出所有元素

    数组复制:
    要使用${ARRAY[@]}
    $@: 每个参数是一个独立的串
    $*: 所有参数是一个串

    向数组中追加元素:非稀疏格式
    week, 
    week[${#week[@]}]

    从数组中删除元素:
    unset ARRAY[index]

    例:复制一个数组中下标为偶数的元素至一个新数组中
    #!/bin/bash
    declare -a mylogs
    logs=(/var/log/*.log)
    echo ${logs[@]}
    for i in `seq 0 ${#logs[@]}`; do
        if [ $[$i%2] -eq 0 ];then
            index=${#mylogs[@]}
             mylogs[$index]=${logs[$i]}
        fi
    done
    echo ${mylogs[@]} 

    例:生成10个随机数,升序排序
    #!/bin/bash
    for((i=0;i<10;i++))
    do
        rnd[$i]=$RANDOM
    done
    echo -e "total=${#rnd[@]} ${rnd[@]} Begin to sort"
    for((i=9;i>=1;i--))
    do
            for((j=0;j<i;j++))
        do
        if [ ${rnd[$j]} -gt ${rnd[$[$j+1]]} ] ;then
            swapValue=${rnd[$j]}
            rnd[$j]=${rnd[$[$j+1]]}
            rnd[$[$j+1]]=$swapValue     
        fi
        done
    done
    echo ${rnd[@]} 

    例:打印九九乘法表
    #!/bin/bash
    for((i=1;i<=9;i++))
    do 
    strLine=""
        for((j=1;i<=9;j++))
        do
            strLine=$strLine"$i*$j="$[$i*$j]" "
            [ $i -eq $j ] && echo -e $strLine && break
        done
    done 

    字符串操作

    字符串切片
    ${string:offset:length}
    举例:
    string='hello word'
    echo ${string:2:4}
    llo 

    取尾部的指定个数的字符:
    ${string: -length}
    举例:
    echo ${string: -2}
    rd 

    取子串:基于模式
    ${variable#*word}:在variable中存储字串上,自左而右,查找第一次出现word,删除字符开始至此word处的所有内容;
    ${variable##*word}:在variable中存储字串上,自左而右,查找最后一次出现word,删除字符开始至此word处的所有内容;
    举例:
    file='/var/log/messages'
    ${file#*/}: 返回的结果是var/log/messages
    ${file##*/}: 返回messages 

    ${variable%word*}: 在variable中存储字串上,自右而左,查找第一次出现word,删除此word处至字串尾部的所有内容;
    ${variable%%world*}:在variable中存储字串上,自右而左,查找最后一次出现word,删除此word处至字串尾部的所有内容;
    举例:
    file='/var/log/messages'
    ${file%*/}: 返回的结果是/var/log
    ${file%%*/}: 返回结果为空 

    例:url="http://www.redhat.com:80" 
    取端口:${url##*:}
    取协议:${url%%:*} 

    查找替换:
    ${variable/pattern/substi}: 替换第一次出现
    #userinfo=`tail -1 /etc/passwd
    #echo $userinfo
    scholar:x:500:500:scholar:/home/scholar:/bin/bash
    #echo ${userinfo/scholar/redhat}
    redhat:x:500:500:scholar:/home/scholar:/bin/bash 

    ${variable//pattern/substi}:替换所有的出现
    #echo ${userinfo//scholar/redhat}
    redhat:x:500:500:redhat:/home/redhat:/bin/bash 

    ${variable/#pattern/substi}:替换行首被pattern匹配到的内容
    #echo ${userinfo/#scholar/redhat}
    redhat:x:500:500:scholar:/home/scholar:/bin/bash 

    ${variable/%pattern/substi}:替换行尾被pattern匹配到的内容
    #echo ${userinfo/%bash/redhat}
    scholar:x:500:500:scholar:/home/scholar:/bin/redhat 

    pattern可以使用globbing中的元字符:* ?

    查找删除:
    ${variable/pattern}:删除第一次出现
    #echo ${userinfo/scholar}
    :x:500:500:scholar:/home/scholar:/bin/bash 

    ${variable//pattern}:删除所有的出现
    #echo ${userinfo//scholar}
    :x:500:500::/home/:/bin/bash 

    ${variable/#pattern}:删除行首被pattern匹配到的内容
    #echo ${userinfo/#scholar}
    :x:500:500:scholar:/home/scholar:/bin/bash 

    ${variable/%pattern}:删除行尾被pattern匹配到的内容
    #echo ${userinfo/%bash}
    scholar:x:500:500:scholar:/home/scholar:/bin/ 


    大小写转换:
    小-->大:${variable^^}
    #echo ${userinfo^^}
    SCHOLAR:X:500:500:SCHOLAR:/HOME/SCHOLAR:/BIN/BASH 

    大-->小:${variable,,}
    #name="SCHOLAR"
    #echo ${name,,}
    scholar 


    变量赋值操作:
    ${variable:-string}:variable为空或未设定,那么返回string,否则,返回variable变量的值;
    ${variable:=string}:variable为空或未设定,则返回string,且将string赋值给变量variable,否则,返回variable的值;
    为脚本使用配置文件,并确保某变量有可用值的方式
    variable=${variable:-default vaule}

    写个脚本,配置etc目录;
    (1) 在配置文件中定义变量;
    (2) 在脚本中source配置文件;
    #!/bin/bash
    [ -f /etc/sysconfig/network ] && source /etc/network/network
    [-z "$HOSTAME" -o "$HOSTNAME" = '(none)' ] || HOSTNAME ='localhost'
    /bin/hostname $HOSTNAME
    /bin/hostname 


    补充

    mktemp命令:

    mktemp [OPTIONS] filename.XXX
    -d: 创建临时目录
    --tmpdir=/path/to/somewhere :指定临时文件所在的目录 

    mktemp /tmp/tmp.XXX                    #XXX生成相同数量随机字符
    mktemp --tmpdir=/var/tmp tmp.XXX       #指定目录创建临时文件
    mktemp --tmpdir=/var/tmp -d tmp.XXX    #指定目录创建临时目录 


    install命令:
    install [OPTIONS] SOURCE DEST
    install [OPTIONS] SOURCE... DIR
    install [OPTIONS] -d DIR ...

    增强型的复制命令:
    -o OWNER
    -g GROUP
    -m MODE 
    -d : 创建目录 

    install /etc/fstab /tmp                 #复制文件到指定目录
    install --mode=644 /etc/fstab /tmp/     #复制时指定权限
    install --owner=scholar /etc/fstab /tmp #复制时指定属主
    install --group=scholar /etc/fstab /tmp #复制时指定属组
    install -d /tmp/install                 #创建目录 





  • 相关阅读:
    Tinyhttpd 代码学习
    Windows noinstall zip 安装MySQL。
    Java 优先队列
    Java Comparable 和 Comparator
    Centos6.6下安装Python3.5
    对象的实现
    对象接口
    适配器模式
    java基础学习(一)
    【MongoDB】如何注册windows服务
  • 原文地址:https://www.cnblogs.com/tsw1107/p/a448aa8e3b389f711f61d302b235d71c.html
Copyright © 2020-2023  润新知