• shell脚本系列:编程风格


    函数名

    小写字母、下划线:

    # Single function
    my_func() {
      ...
    }
    
    # Part of a package
    mypackage::my_func() {
      ...
    }
    

    变量名

    小写字母、下划线、循环变量:

    for zone in ${zones}; do
        something_with "${zone}"
    done
    

    只读变量

    使用readonly或者declare -r声明:

    zip_version="$(dpkg --status zip | grep Version: | cut -d ' ' -f 2)"
    if [[ -z "${zip_version}" ]]; then
        error_message
    else
        readonly zip_version
    fi
    

    常量和环境变量

    大写字母:

    # Constant
    readonly PATH_TO_FILES='/some/path'
    
    # Both constant and environment
    declare -xr ORACLE_SID='PROD'
    
    VERBOSE='false'
    while getopts 'v' flag; do
        case "${flag}" in
            v) VERBOSE='true' ;;
        esac
    done
    readonly VERBOSE
    

    使用本地变量

    local声明:

    my_func2() {
    local name="$1"
    
    # Separate lines for declaration and assignment:
    local my_var
    my_var="$(my_func)" || return
    
    # DO NOT do this: $? contains the exit code of 'local', not my_func
    local my_var="$(my_func)"
    [[ $? -eq 0 ]] || return
    
    ...
    }
    

    源文件名

    小写字母、下划线:

    make_template.sh
    

    打印错误信息

    err() {
        echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $@" >&2
    }
    
    if ! do_something; then
        err "Unable to do_something"
        exit "${E_DID_NOTHING}"
    fi
    

    基本语句格式

    缩进四个空格,或者一个制表符,一个制表符设置为四个空格。

    行的长度最大为80字符,使用换行。

    管道:如果一行容得下整个管道操作,那么请将整个管道操作写在同一行。否则,应该将整个管道操作分割成每行一个管段,管道操作的下一部分应该将管道符放在新行并且缩进2个空格。这适用于使用管道符’|’的合并命令链以及使用’||’和’&&’的逻辑运算链。

    # All fits on one line
    command1 | command2
    
    # Long commands
    command1 
      | command2 
      | command3 
      | command4
    

    for循环

    请将 ; do , ; then 和 while , for , if 放在同一行。

    for dir in ${dirs_to_cleanup}; do
        if [[ -d "${dir}/${ORACLE_SID}" ]]; then
            log_date "Cleaning up old files in ${dir}/${ORACLE_SID}"
            rm "${dir}/${ORACLE_SID}/"*
            if [[ "$?" -ne 0 ]]; then
                error_message
            fi
        else
            mkdir -p "${dir}/${ORACLE_SID}"
            if [[ "$?" -ne 0 ]]; then
            error_message
            fi
        fi
    done
    

    case语句

    case "${expression}" in
        a)
            variable="..."
            some_command "${variable}" "${other_expr}" ...
            ;;
        absolute)
            actions="relative"
            another_command "${actions}" "${other_expr}" ...
            ;;
        *)
            error "Unexpected expression '${expression}'"
            ;;
    esac
    
    verbose='false'
    aflag=''
    bflag=''
    files=''
    while getopts 'abf:v' flag; do
        case "${flag}" in
            a) aflag='true' ;;
            b) bflag='true' ;;
            f) files="${OPTARG}" ;;
            v) verbose='true' ;;
            *) error "Unexpected option ${flag}" ;;
        esac
    done
    

    变量扩展

    用 ({var} 而不是 )var ,详细解释如下:

    • 与现存代码中你所发现的保持一致。
    • 引用变量参阅下面一节,引用。
    • 除非绝对必要或者为了避免深深的困惑,否则不要用大括号将单个字符的shell特殊变量或定位变量括起来。推荐将其他所有变量用大括号括起来。

    引用

    set -- 1 "2 two" "3 three tres"; echo $# ; set -- "$*"; echo "$#, $@"
    set -- 1 "2 two" "3 three tres"; echo $# ; set -- "$@"; echo "$#, $@"
    

    命令替换

    使用 $(command) 而不是反引号`command`。
    

    test、[和[[

    推荐使用 [[ ... ]] ,而不是 [ , test , 和 /usr/bin/ [ 。

    if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
        echo "Match"
    fi
    
    if [[ "filename" == "f*" ]]; then
        echo "Match"
    fi
    

    测试字符串

    if [[ "${my_var}" = "some_string" ]]; then
        do_something
    fi
    
    if [[ -n "${my_var}" ]]; then
        do_something
    fi
    # string不空时为真
    
    if [[ -z "${my_var}" ]]; then
        do_something
    fi
    # string空时为真
    
    if [[ "${my_var}" = "" ]]; then
        do_something
    fi
    # string空时为真
    

    文件名的通配符扩展

    因为文件名可能以 - 开头,所以使用扩展通配符 ./* 比 * 来得安全得多。

    rm -v ./*    # 好
    rm -v *    # 不好
    

    管道导向while循环

    管道导向while循环中的隐式子shell使得追踪bug变得很困难。

    last_line='NULL'
    your_command | while read line; do
        last_line="${line}"
    done
    
    echo "${last_line}"
    

    如果你确定输入中不包含空格或者特殊符号(通常意味着不是用户输入的),那么可以使用一个for循环。

    total=0
    for value in $(command); do
        total+="${value}"
    done
    

    使用过程替换允许重定向输出,但是请将命令放入一个显式的子shell中,而不是bash为while循环创建的隐式子shell。

    total=0
    last_file=
    while read count filename; do
        total+="${count}"
        last_file="${filename}"
    done < <(your_command | uniq -c)
    
    echo "Total = ${total}"
    echo "Last one = ${last_file}"
    

    当不需要传递复杂的结果给父shell时可以使用while循环。这通常需要一些更复杂的“解析”。请注意简单的例子使用如awk这类工具可能更容易完成。当你特别不希望改变父shell的范围变量时这可能也是有用的。

    cat /proc/mounts | while read src dest type opts rest; do
        if [[ ${type} == "nfs" ]]; then
            echo "NFS ${dest} maps to ${src}"
        fi
    done
    

    检查返回值

    mv "${file_list}" "${dest_dir}/"
    if [[ "$?" -ne 0 ]]; then
        echo "Unable to move ${file_list} to ${dest_dir}" >&2
        exit "${E_BAD_MOVE}"
    fi
    
  • 相关阅读:
    设计模式(Design Pattern)扫盲
    SharePoint 2007 采用表单验证 (1) 失败:(
    发布一款给图片批量加水印的程序PicNet V1.0
    转篇文章,VS2005开发的dll如何安装进GAC
    cnblogs排名进入1500,纪念一下
    转载一篇提高baidu/google收录的文章
    关于.NET(C#)中字符型(Char)与数字类型的转换, CLR via c# 读书笔记
    《天风文章》V1.2.0 新闻/文章类asp.net2.0站点系统源码 (100%开源)
    推荐个.Net的论坛系统 Discuz!NT
    C#实现对图片加水印的一段代码.
  • 原文地址:https://www.cnblogs.com/iuskye/p/shell-style.html
Copyright © 2020-2023  润新知