zoukankan      html  css  js  c++  java
  • 入门 shell 从脚本开始


    编写脚本实现在指定文件路径下查找文件夹或文件名。
     
    脚本如下:
    #!/bin/sh
    # lazy find
     
    # GNU All-Permissive License
    # Copying and distribution of this file, with or without modification,
    # are permitted in any medium without royalty provided the copyright
    # notice and this notice are preserved.  This file is offered as-is,
    # without any warranty.
     
    ## help function
     
    function helpu {
        echo " "
        echo "Fuzzy search for filename."
        echo "$0 [--match-case|--path] filename"
        echo " "
        exit
    }
     
    ## set variables
     
    MATCH="-iname"
    SEARCH="."
     
    ## parse options
     
    while [ True ]; do
    if [ "$1" = "--help" -o "$1" = "-h" ]; then
        helpu
    elif [ "$1" = "--match-case" -o "$1" = "-m" ]; then
        MATCH="-name"
        shift 1
    elif [ "$1" = "--path" -o "$1" = "-p" ]; then
        SEARCH="${2}"
        shift 2
    else
        break
    fi
    done
     
    ## sanitize input filenames
    ## create array, retain spaces
     
    ARG=( "${@}" )
    set -e
     
    ## catch obvious input error
     
    if [ "X$ARG" = "X" ]; then
        helpu
    fi
     
    ## perform search
     
    for query in ${ARG[*]}; do
        /usr/bin/find "${SEARCH}" "${MATCH}" "*${ARG}*"
    done
    该脚本来自网络,非常简洁,优雅。
     
    通过该脚本来学习 shell,脚本中包括如下几个 shell 知识点:
    • Shebang 行
    • 变量
    • 循环
    • 列表
    • 参数
    • 函数
    • 判断
    • set
    ## Shebang 行
    Shebang 行是脚本的第一句,通常记为 #!/bin/bash 这种形式,指定执行该脚本需要用到的解释器。如果不加,在执行脚本的时候可通过命令 /bin/bash 指定。
     
    ## 变量
    变量在 shell 中写作 variable=value 的形式(等号两边不能有空格!),variable 为变量名,value 为变量的值。
     
    变量名需遵守以下命名规则:
    • 由字母,数字,下划线组成。
    • 变量名开头不能是数字,可以是字母或下划线。
    • 变量名中不允许出现空格和标点符号。
     
    shell 将所有 value 看作字符串,如果 value 有空格,则需使用引号将 value 括起来。
     
    常用的几种变量写法:
    MATCH="-iname"
    MATCH=-iname
     
    NAME="lian hua"
     
    可通过在变量名前加美元符 $ 或加大括号 ${variable} 的形式引用变量:
    echo $MATCH
     
    echo ${MATCH}
     
    注意,bash 读取不存在的变量,不会报错,会打印出空字符,如下:
    [lianhuasheng@demo home]$ echo $lianhua
     
    [lianhuasheng@demo home]$ 
     
    在脚本执行的时候,如果变量不存在一般会期望脚本报错,这时候 set 命令就派上用场了。
     
    ## set
    set 可用来设置子 shell 的运行环境,不加任何参数的 set 会 show 出当前 shell 的自带环境变量和自定义环境变量等。另一方面,set 也可用来编写更安全的 shell 脚本。
     
    set -e 命令可使得在其后执行的命令,如果失败了即报错,后续的命令将不被执行。如果期望命令执行失败后,后续命令还能继续执行,可打开 set +e 选项:
    set -e
     
    command1
    command2
     
    set +e
     
    set -u 可使得bash 在读取不存在变量的时候报错。
     
    ## 循环
    在上例中使用到了 while 和 for 循环:
     
    while 循环的语法格式如下:
    while condition; do
        commands
    done
     
    for 循环的语法格式有三种,分别是:
    ## 1. normal for script
    for variable in list; do
        commands
    done
     
    ## demo for script 
    #!/bin/bash
     
    for i in lian hua sheng; do
      echo $i
    done
     
    ## 2. c style for script
    for (( expression1; expression2; expression3 )); do
      commands
    done
    其中,c 语言风格的 for 循环中,expression1 用来设置循环初始值,expression2 用来设置循环结束条件,expression3 用来更新值。
     
    ## 列表
    上小节看到 for 循环中的循环体是 list 列表,列表可通过大括号扩展或者参数传递等的形式取得。
     
    # 大括号扩展
    使用大括号扩展 {start..end} 形式扩展值为列表:
    [lianhuasheng@demo home]$ echo {1..10}
    1 2 3 4 5 6 7 8 9 10
     
    将扩展出的列表运用于 for 循环中:
    [lianhuasheng@demo home]$ echo {1..10}
    1 2 3 4 5 6 7 8 9 10
    注意,默认 echo 输出的文本文件后加 换行符,所以这里指定 echo 的 -n 选项取消换行符。
     
    # 参数传递
    除了大括号扩展,还有一种常见的组成列表的形式是参数传递。参数传递,即在执行脚本时指定的参数,shell 脚本中分别使用如下几种符号表明参数:
    • $0: 脚本文件名。
    • $1 - $9: 脚本的第 1 个参数到第 9 个参数,超过 9 个参数使用 ${10}, ${11}... 形式表示。
    • $#: 传入脚本的参数数量。
    • $@: 传入脚本中的全部参数,它是一个列表。
    [lianhuasheng@demo home]$ cat parameter.sh
    #!/bin/bash
    # script.sh
     
    echo "all parameters:" $@
    echo "number of parameters:" $#
    echo '$0 = ' $0
    echo '$1 = ' $1
    echo '$2 = ' $2
    echo '$3 = ' $3
     
    [lianhuasheng@demo home]$ ./parameter.sh lian hua
    all parameters: lian hua
    number of parameters: 2
    $0 =  ./parameter.sh
    $1 =  lian
    $2 =  hua
    $3 =                            # $3 没有读取参数,并没有报错
     
    在 for 循环中常用 $@ 作为循环体:
    for value in "$@"; do
        echo ${value}
    done
     
    ## 数组
    for 循环中还可将数组作为循环体,在上例脚本中看到这样一条语句 ARG=("$@"),其中圆括号 () 即是将字符串转为数组的符号。
     
    # 创建数组
    创建数组有多种方式:直接赋值,间接赋值,外部赋值等方式:
     
    1. 直接赋值:
    [lianhuasheng@demo home]$ arg=(lian hua sheng)
    [lianhuasheng@demo home]$ echo ${arg[@]}
    lian hua sheng
     
    2. 间接赋值:
    [lianhuasheng@demo home]$ arg[0]=da
    [lianhuasheng@demo home]$ arg[1]=shuai
    [lianhuasheng@demo home]$ arg[2]=ge
    [lianhuasheng@demo home]$ echo ${arg[@]}
    da shuai ge
     
    3. 外部赋值:
    [lianhuasheng@demo home]$ read -a arg
    hei hei hei
    [lianhuasheng@demo home]$ echo ${arg[@]}
    hei hei hei
     
    外部赋值通过使用 read 命令,将用户的输入读入到数组 arg 中。
     
    # 读取数组
    通用的读取数组中的元素有两种方式:读取单个元素和读取所有元素:
     
    1. ${arg[index]} 读取单个元素:
    [lianhuasheng@demo home]$ echo ${arg[@]}
    da shuai ge
    [lianhuasheng@demo home]$ echo ${arg[1]}
    shuai
     
    2. 读取所有元素:
    [lianhuasheng@demo home]$ echo ${arg[@]}
    da shuai ge
     
    [lianhuasheng@demo home]$ echo ${arg[*]}
    da shuai ge
     
    通过 ${array[@]} 和 ${array[*]} 都可读取数组的所有元素,$array[*] 相当于不加双引号的 $array[@],加不加双引号的区别可看下例:
    [lianhuasheng@demo home]$ arg=(lian "hua sheng" da "shuai-ge")
     
    [lianhuasheng@demo home]$ for value in ${arg[*]}; do echo "parameter: " ${value}; done
    parameter:  lian
    parameter:  hua
    parameter:  sheng
    parameter:  da
    parameter:  shuai-ge
     
    [lianhuasheng@demo home]$ for value in "${arg[*]}"; do echo "parameter: " ${value}; done
    parameter:  lian hua sheng da shuai-ge
     
    [lianhuasheng@demo home]$ for value in ${arg[@]}; do echo "parameter: " ${value}; done
    parameter:  lian
    parameter:  hua
    parameter:  sheng
    parameter:  da
    parameter:  shuai-ge
     
    [lianhuasheng@demo home]$ for value in "${arg[@]}"; do echo "parameter: " ${value}; done
    parameter:  lian
    parameter:  hua sheng
    parameter:  da
    parameter:  shuai-ge
     
    从示例中可以看出,当 $array[@] 加上双引号之后可正确输出数组 arg 中的元素,不加双引号的 $array[@] 和 $array[*] 的结果一致,加了双引号的 $array[*] 会将数组中所有元素作为单个字符串返回。
     
    注意,不加索引读取数组元素读到的是第一个数组元素:
    [lianhuasheng@demo home]$ echo $arg
    lian
    [lianhuasheng@demo home]$ echo ${arg}
    lian
    [lianhuasheng@demo home]$ echo $arg[0]
    lian[0]
    [lianhuasheng@demo home]$ echo ${arg}[0]
    lian[0]
     
    通过 $arg 和 ${arg} 两种方式读取数组第一个元素,通常两种方式读取变量的结果是一致的,不过推荐使用 ${ } 这种方式读取变量,它可以精确界定变量名称的范围。
    如果读取变量时不用大括号,则 bash 会解析 $arg, 然后将 [0] 原样输出。
     
    ## 条件判断
    条件判断是使用 if..elif..fi 根据指定条件判断命令执不执行的判断语句,它的语法如下:
    if conditions; then
        commands
    elif conditions; then
        commands
    else
        commands
    fi
     
    其中,elif 和 else 是可选的。
     
    条件判断有多种判断表达式,如下:
    • 文件判断
    • 字符串判断
    • 整数判断
    • 正则判断
    • test 判断逻辑运算
    • 算术判断
    • 普通命令的逻辑运算
     
    这里,脚本中的判断表达式皆属于字符串判断,其判断表达式为:
    • [ string ]:string 不为空,则判断为真。
    • [ string1 = string2 ]:string1 和 string2 字符串相同则判断为真,同 [ string1 == string2 ]。
    • [ string1 != string2 ]:string1 和 string2 不同则判断为真。
    • [ -n string ]:string 长度大于 0 则判断为真。
    • [ -z string ]:string 长度等于 0 则判断为真。
     
    注意,这里判断表达式也使用到了 test 命令,test 有三种形式,分别是:
    # 1 style of test
    test expression
     
    # 2 style of test
    [ expression ]
     
    # 3 style of test
    [[ expression ]]
     
    所以,[ -n string ] 判断表达式又可写成 test -n string 这种形式。
     
    关于其它判断表达式的使用可看这里
     
    ## 函数
    shell 中有两种函数写法:
    # 1 style of function
    function fn {
        commands
    }
     
    # 2 style of function
    fn() {
        commands
    }
     
    介绍函数主要从以下几个角度入手:函数参数,函数返回值和函数变量:
     
    # 函数参数
    通常执行脚本传递的参数即可作为函数的参数,但是函数也支持自定义传参:
    #!/bin/bash
     
    function input_param {
        echo "I am input function, the input parameters are: "
        echo "$@"
    }
     
    function input_defined_param {
        echo "I am input defined function, the defined parameters are: "
        echo "The first parameter is: " "${1}"
        echo "The second parameter is: " "${2}"
        echo "The totally parameters are: " "${@}"
    }
     
    input_param ${@}
    input_defined_param lian hua
     
    和脚本中参数类似,函数中也可使用 ${1}/${@}/$#/$* 等参数符号。但是,函数使用特殊参数环境作为自己的参数值,它无法直接获取脚本在命令行中的参数值。因此,需要传递参数给函数。
     
    # 函数返回值
    函数中可使用 return 返回函数执行结果,在调用函数之后可使用 $? 查看函数返回结果:
    [lianhuasheng@demo home]$ ./function_return.sh
    127
    [lianhuasheng@demo home]$ cat function_return.sh
    #!/bin/bash
     
    function_return() {
        return 127
    }
     
    function_return
    echo $?
     
    其中,$? 是 bash 提供的特殊变量,它是上一条命令的退出码,如果 $? 为 0 则表示命令执行成功,非零表示执行失败:
    [lianhuasheng@demo home]$ cd lianhua
    -bash: cd: lianhua: No such file or directory
    [lianhuasheng@demo home]$ echo $?
    1
     
    [lianhuasheng@demo home]$ cd query/
    [lianhuasheng@demo query]$ echo $?
    0
     
    除了 return 返回函数结果之外,在函数或者脚本中也可使用 exit 返回退出码,bash 会读取返回的退出码,并且脚本 exit 之后的语句不会被执行。
    [lianhuasheng@demo home]$ cat function_exit.sh
    #!/bin/bash
     
    function_exit() {
        exit 127
    }
     
    function_exit
    echo "kissMe"
    [lianhuasheng@demo home]$ ./function_exit.sh       # echo "kissMe" 没有执行到
    [lianhuasheng@demo home]$ echo $?
    127
    [lianhuasheng@demo home]$ vi function_exit.sh
    [lianhuasheng@demo home]$ ./function_exit.sh
    [lianhuasheng@demo home]$ echo $?
    0
     
    # 函数变量
    函数中声明的变量都是全局变量,可使用 local 将变量转为局部变量:
    [root@demo bash]# cat function_variable.sh
    #!/bin/bash
     
    name="lian hua"
     
    function rename {
        echo "My original name is: " "${name}"
        name="${1}"
        echo "Now, My name is: " "${name}"
    }
     
    function naming {
        initName="lao wang"
    }
     
    naming
    echo ${initName}                   # 函数外可以使用函数内定义的变量
     
    rename "shuai ge"
    echo "once again, my name is: " "${name}"          # 函数内可以修改函数外定义的全局变量
     
    [root@demo bash]# ./function_variable.sh
    lao wang
    My original name is:  lian hua
    Now, My name is:  shuai ge
    once again, my name is:  shuai ge
     
    [root@demo bash]# cat function_variable.sh
    #!/bin/bash
    function naming {
        firstName="wang"
        local lastName="lao"
    }
     
    naming
    echo ${firstName}
     
    set -eux
    echo ${lastName}
    set +eux
     
    [root@demo bash]# ./function_variable.sh
    wang
    ./function_variable.sh: line 12: lastName: unbound variable         # lastName 是局部变量,无法引用
     
     
  • 相关阅读:
    CUDA实例练习(十二):矩阵相乘
    CUDA实例练习(十一):零拷贝内存
    CUDA实例练习(十):多个cuda流
    CUDA实例练习(九):页锁定主机内存
    CUDA实例练习(八):原子操作(直方图)
    算法实例(三):快速排序
    算法实例(二):冒泡排序
    算法实例(一):简单桶排序
    CUDA实例练习(七):点积运算
    CUDA实例练习(六):矢量求和
  • 原文地址:https://www.cnblogs.com/xingzheanan/p/13461250.html
Copyright © 2011-2022 走看看