Linux shell脚本

作者:海鹰
此教程讲述如何编写shell脚本
版权所有,未经允许,请勿随意转载。

1. 使用shell

Linux提供多个shell解释器给用户选择。

登录后进入用户指定的shell

编辑/etc/passwd文件,找到需要修改shell的用户名,修改行末尾的shell程序。

使用chsh命令改变用户登录后进入的shell

临时改变正在使用的shell

2. bash程序设计

  1. shell程序就是把用户输入的shell命令按照控制结构组织到一个文本文件中,批量地交给shell去执行。
  2. shell程序是通过shell命令解释器执行的,不生成二进制的可执行代码。
  3. shell程序又称shell脚本程序,不同的shell解释器编制脚本程序的语法不完全相同。

#! /bin/bash

  1. 程序的第1行指定了采取的shell脚本解释器。它由“#!”开始,其后是解释器的路径。
  2. 如果采用其他解释器,可以用相应的路径替换/bin/bash。

注释

shell脚本中采用#作为注释符号。以#开始的注释只在本行起作用,多行注释需要在每行之前都加上#号。

其它

  1. 将文件保存为.sh文件类型。
  2. 需要赋予文件可执行权限:chmod +x HelloWorld.sh
  3. echo $?,输出变量“?”的值,“$?”是检查前驱命令返回值的常用方法。

3. 变量

bash脚本语言是一种弱类型的脚本语言。所谓弱类型脚本语言,是指这种语言对类型的要求不严格,同一个变量随着使用场合的不同,可以存储不同类型的数据。

赋值

变量=值
注意:等号两侧不能有空格
比如:a=”hello”

引用

  1. 引用一个变量可以在变量名前加一个$
    比如:echo “$a world”

  2. 引用变量还可以采用:${变量名}
    比如:echo “${a} world”

  3. 第二种引用方式还有以下几种常用的扩展用法
    ${variable: -value}:如果变量variable存在,则返回variable的值,否则返回value。
    ${variable: =value}:如果变量variable存在,则返回variable的值,否则,先将value赋给变量variable,然后返回值value。
    ${variable: +value}:如果变量variable存在,则返回值value,否则返回控制。
    ${variable:?value}:如果变量variable存在,则返回variable的值,否则将value送到标准错误输出显示并退出shell程序,这里的value通常为一个错误提示消息。
    ${variable: offset[: length]}:返回从变量variable的第(offset+1)个字符开始的、长度为length的子串,如果中括号内的部分省略,则返回其后的所有子串。

  4. 要指明表达式是一个运算式,可以使用expr命令和let命令。

expr

  1. 格式:expr arg,arg代表一个表达式,表达式是一个由运算符和操作数连接起来的字符串。

  2. expr命令根据运算符的类型来判断操作数的类型,另外,操作数和运算符之间要用空白字符隔开,否则,expr计算错误。

  3. 在表达式中有通配符(如“ * ”)时,要采用转义字符“\”或者引号(单引号或双引号)。
    比如:
    expr 3 * 2 错误
    expr 3 \* 2 正确
    expr 3 ‘*‘ 2 正确
    expr 3 “*“ 2 正确

  4. 当表达式比较复杂、含有不同优先级的运算符时,最好采用把复杂的表达式拆分成几个简单的表达式的方法。
    比如:
    s = `expr 2 + 3`
    expr $s \* 4
    或 expr `expr 2 + 3` \* 4
    注意,这里使用了反向引号(`)

let

  1. 格式:let arg1 [arg2…],其中,中括号表示可以有多个参数,argN(N=1,2,3……)为表达式。每个表达式内的运算符和操作数之间不必用空格分开。

  2. let命令可以一次对多个表达式进行计算。

  3. 当表达式中含有<、>、&、|等特殊符号时,需要用转义字符“\”或者引号(单引号或双引号)放在特殊符号前面。

  4. 示例
    let s = (2+3)*4

4. 条件判断

  1. 在shell程序中,0表示真,非0表示假,这一点与C语言恰恰相反。

  2. 在bash中,对条件进行判断的命令是test和中括号[ ],二者是等价的。
    使用格式是:
    test condition

    [ condition ]

  3. 利用中括号[ ]进行判断时,左、右中括号和判断条件之间要用空格分隔开。

  4. condition为需要判断的条件,可以是:
    文件属性的测试,包括文件类型、文件访问权限等
    字符串属性的测试,包括字符串长度、内容等
    整数关系的测试,包括比较大小、相等判断等

  5. 逻辑运算
    逻辑与-a:condition1 -a condition2
    逻辑或-o:condition1 -o condition2
    逻辑非!:!condition

测试文件属性

  1. 常用文件属性判断
    -f fn:fn是否存在且为普通文件
    -b fn:fn是否存在且为块设备
    -e fn:fn是否存在
    -d fn:fn是否存在且为目录
    -r fn:fn是否存在且可读
    -w fn:fn是否存在且可写
    -x fn:fn是否存在且可执行
    -O fn:fn是否存在且被当前用户拥有
    -L fn:fn是否存在且为符号链接

  2. 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 文件是否存在且可写
    [root@localhost shell]# test -w test.sh
    [root@localhost shell]# echo $?
    0
    # 文件是否为目录,且可写
    [root@localhost shell]# test -d test.sh -a -w test.sh
    [root@localhost shell]# echo $?
    1
    # 文件是否可读,并且可写
    [root@localhost shell]# test -r test.sh -a -w test.sh
    [root@localhost shell]# echo $?
    0

测试字符串属性

  1. 常用字符串属性条件判断
    string_1 = string_2:string_1和string_2是否相等
    string_1 != string_2:string_1和string_2是否不相等
    -z string:string的长度是否为0
    -n string:string的长度是否不为0
    string:等同于-n string

测试整数关系

  1. 常用整数关系条件判断
    num_1 -eq num_2:num_1是否等于num_2
    num_1 -ne num_2:num_1是否不等于num_2
    num_1 -gt num_2:num_1是否大于num_2
    num_1 -lt num_2:num_1是否小于num_2
    num_1 -ge num_2:num_1是否大于等于num_2
    num_1 -le num_2:num_1是否小于等于num_2

5. 控制结构

if

  1. 语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if 条件1
    then
    命令
    [elif 条件2
    then
    命令]
    [else
    命令]
    fi
  2. 当要求if的判断条件和then同在一行时,必须要在判断条件和then命令之间,增加一个分号作为分隔符

    1
    2
    3
    4
    5
    6
    7
    if 条件1 ;then
    命令
    [elif 条件2 ;then
    命令]
    [else
    命令]
    fi

case

  1. 语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    case 条件 in
    模式1)
    命令1
    ;;
    [模式2)
    命令2
    ;;
    ...
    模式n)
    命令n
    ;;]
    esac
  2. “条件”可以是变量、表达式、shell命令等。

  3. “模式”为条件的值,并且一个“模式”可以匹配多种值,不同值之间用竖线(|)联结。模式还可以使用通配符,星号(*)匹配任意字符,问好(?)匹配任意单个字符,[…]匹配某个范围内的字符等。

  4. 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    case $test in
    y|Y|yes|Yes)
    echo "OK"
    ;;
    n|N|no|No)
    echo "NO"
    ;;
    *)
    echo "Have a look"
    ;;
    esac

for

  1. 语法

    1
    2
    3
    4
    for 变量 [in 列表]
    do
    命令(通常用到循环变量)
    done
  2. “列表”为存储一系列值的列表,随着循环的进行,变量从列表的第一个值依次取到最后一个值。如果省略中括号部分,bash则认为是“in $@”,即执行该程序时,通过命令行传给程序的所有参数的列表。

  3. 示例

    1
    2
    3
    4
    for os in Linux Windows Unix
    do
    echo "Operation System is: $os"
    done

while和until

  1. 语法
    1
    2
    3
    4
    while/until 条件
    do
    命令
    done

6. 函数

  1. 语法

    1
    2
    3
    4
    [function]函数名()
    {
    命令
    }
  2. function可以省略。

  3. 调用函数的格式:函数名 [ 参数1 参数2 …… 参数n ]

  4. 是否需要参数由函数的定义和功能决定,参数与参数之间用空格分隔。如果在函数内部需要使用传递给函数的参数,一般使用$0、$1、……、$n,以及$#、$*、$@这些特殊变量。$0为执行脚本的函数名,$1表示第一个参数,依次类推,$n为第n个参数;$#为传递给函数的参数个数;$*和$@为传递给函数的所有参数,两者的区别是,$*把所有参数作为一个整体,而$@把所有参数看做拥有多个参数的集合,可以单独访问每个参数。

  5. 当向一个完整的shell脚本程序传递参数时,shell程序同样可以通过这些特殊变量来访问传递的参数。这时,这些参数来自终端的命令行,把脚本文件名看做函数名,所有特殊变量的含义和向函数传递时的含义完全一样。

  6. 另外,在访问传递的参数时,采用shift命令也是一种常用的方式。shift命令用于将存储在位置变量($1、$2、……、$n)中的变量左移一个位置。

  7. shell程序中的函数也可以有返回值。使用return命令从函数返回值。

7. 示例

结语

本教程到此结束,欢迎指正,互相交流。
版权所有,未经允许,请勿随意转载。