一、变量

1、命名规则

  • 变量名和等号之间不能有空格
  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
  • 变量名中间不能有空格,可以使用下划线(_)
  • 不能使用标点符号
  • 不能使用bash里的关键字(可用help命令查看保留关键字)

    2、变量声明示例如下

    1. your_name="xxxx"
    2. _var2=123
    3. user*name=tom ×,无效的变量名

    3、使用变量

    使用一个定义过的变量,只要在变量名前面加美元符号(只有在使用时才加$)即可,变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界。建议加上

    1. your_name="qinjx"
    2. echo $your_name
    3. echo ${your_name} ## 帮助解释器识别变量的边界

    4、只读变量

    使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变。语法:

    1. readonly var_name

    5、删除变量

    使用unset命令可以删除变量。语法:

    1. unset var_name

    注意:变量被删除后不能再次使用。unset 命令不能删除只读变量。

    6、接收用户输入

    使用read命令用于从终端或文件读取输入,常见的用法如下:

    1. read -p “提示信息” var_name ## 打印提示符,等待输入,并将输入赋值给var_name

    7、变量类型

    运行shell时,会同时存在三种变量:

  • 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。

  • 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。

二、运算符

原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如awkexpr,其中expr最常用。expr是一款表达式计算工具,使用它能完成表达式的求值操作。

1、算术运算符

运算符 说明 举例: a=10, b=20
+ expr $a + $b 结果为 30
- expr $a - $b 结果为 -10
* expr $a \* $b 结果为 200 转义符必须加
/ expr $b / $a 结果为 2
% 取余 expr $b % $a 结果为 0
= 赋值 a=$b 把变量 b 的值赋给 a
== 相等 [ $a == $b ] 返回 false 空格必须加
!= 不相等 [ $a != $b ] 返回 true

2、关系运算符

注意:关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

运算符 说明 举例: a=10, b=20
-eq equal,相等 == [ $a -eq $b ] 返回 false
-ne no equal,不相等 != [ $a -ne $b ] 返回 true
-gt great than,大于, > [ $a -gt $b ] 返回 false
-ge great and equal,大于等于, >= [ $a -ge $b ] 返回 false
-lt low than,小于, < [ $a -lt $b ] 返回 true
-le low and equal,小于等于, <= [ $a -le $b ] 返回 true

3、布尔运算符

运算符 说明 举例: a=10, b=20
! [ ! false ] 返回 true
-o [ $a -lt 20 -o $b -gt 100 ] 返回 true
-a [ $a -lt 20 -a $b -gt 100 ] 返回 false

4、逻辑运算符

运算符 说明 举例: a=10, b=20
&& 逻辑与 [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 逻辑或 [[ $a -lt 100 &#124;&#124; $b -gt 100 ]] 返回 true

5、字符串运算符

运算符 说明 举例: a=”abc”, b=”efg”
= 检测两个字符串是否相等,相等返回 true [ $a = $b ] 返回 false
!= 检测两个字符串是否相等,不相等返回 true [ $a != $b ] 返回 true
-z 检测字符串长度是否为0, 为0返回 true [ -z $a ] 返回 false
-n 检测字符串长度是否为0,不为0返回 true [ -n $a ] 返回 true
$ 检测字符串是否为空,不为空返回 true [ $a ] 返回 true

6、文件测试运算符

文件测试运算符用于检测 Unix 文件的各种属性。下面列举几个常用的测算符。

运算符 说明 举例:file=”/var/test.sh”,大小100字节,具有rwx权限
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false
-f file 检测文件是否是普通文件,如果是,则返回 true。 [ -f $file ] 返回 true
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true

补充知识:linux中文件类型大致分为7种 b: 块设备文件 c: 字符设备文件 d: 目录 -: 普通文件 l: 链接 s: socket p: 管道

三、字符串

字符串可以用单引号,也可以用双引号,也可以不用引号。

1、单引号

  1. str='this is a string'

2、单引号字符串的限制

单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
单引号字串中不能出现单独一个的单引号(对单引号转义也不行),但可成对出现,作为字符串拼接使用。

3、双引号

  1. your_name='tom'
  2. str="Hello, I know you are \"$your_name\"! \n"
  3. echo -e $str ## echo -e 显示换行
  4. echo "OK"
  5. ## Hello, I know you are "tom"!
  6. ##
  7. ## OK

4、双引号的优点

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

    5、拼接字符串

    ```shell your_name=”tom”

使用双引号拼接

greeting_0=”hello, “$your_name”!” greeting_1=”hello, ${your_name}!” echo $greeting_0 $greeting_1 ## hello, tom! hello, tom!

使用单引号拼接

greeting_2=’hello, ‘$your_name’!’ greeting_3=’hello, ${your_name}!’ echo $greeting_2 $greeting_3 ## hello, tom! hello, ${your_name}!

  1. <a name="2ljL9"></a>
  2. #### 6、获取字符串长度
  3. ```shell
  4. string="abcd"
  5. echo ${#string} ## 4

7、提取子字符串

  1. # 从字符串第 2 个字符开始截取 4 个字符:
  2. str="tom is a great man"
  3. echo ${str:1:4} ## om i

8、查找子字符串

  1. # 查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):
  2. str="tom is a great man"
  3. echo `expr index "$str" io` ## 2

注意: 以上脚本中 `` 是反引号,而不是单引号‘`

四、数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。

1、定义数组

在shell中,用括号来表示数组,数组元素用 空格 符号分割开。

  1. ## 定义数组的一般形式为:
  2. 数组名=(值1 2 ... n)
  3. ## 例如:
  4. array_name=(value0 value1 value2 value3 ...)
  5. ## 或者:
  6. array_name=(
  7. value0
  8. value1
  9. value2
  10. value3
  11. )
  12. ## 还可以单独定义数组的各个分量:
  13. array_name[0]=value0
  14. array_name[1]=value1
  15. array_name[n]=valuen
  16. ## 可以不使用连续的下标,而且下标的范围没有限制。

2、读取数组

读取数组元素值的一般格式是:${数组名[下标]}

  1. valuen=${array_name[n]}

使用@符号可以获取数组中的所有元素:echo ${array_name[@]}

3、获取数组的长度

获取数组长度的方法与获取字符串长度的方法相同,如下所示:

  1. # 取得数组元素的个数
  2. length=${#array_name[@]}
  3. # 或者
  4. length=${#array_name[*]}
  5. # 取得数组单个元素的长度
  6. lengthn=${#array_name[n]}

五、函数

1、函数定义格式

  1. function funname(){
  2. action;
  3. return
  4. }

说明:

  • 可以带function fun()定义,也可以直接fun()定义,不带任何参数
  • 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值

    2、函数无参实例(有无返回值)

  1. 无返回值

    1. demoFun(){
    2. echo "这是我的第一个 shell 函数!"
    3. }
    4. echo "-----函数开始执行-----" ## -----函数开始执行-----
    5. demoFun ## 这是我的第一个 shell 函数!
    6. echo "-----函数执行完毕-----" ## -----函数执行完毕-----
  2. 有返回值 ```shell funWithReturn(){ echo “这个函数会对输入的两个数字进行相加运算…” echo “输入第一个数字: “ read aNum echo “输入第二个数字: “ read anotherNum echo “两个数字分别为 $aNum 和 $anotherNum !” return $(($aNum+$anotherNum)) } funWithReturn echo “输入的两个数字之和为 $? !”

这个函数会对输入的两个数字进行相加运算…

输入第一个数字:

1

输入第二个数字:

2

两个数字分别为 1 和 2 !

输入的两个数字之和为 3 !

  1. 注意:函数返回值在调用该函数后通过`$?`来获得,但是`$?`仅对其上一条指令负责,一旦函数返回后其返回值没有立即保存入参数(或者进行输出),那么其返回值将不再能通过 `$?` 获得。
  2. <a name="WVXzO"></a>
  3. ### 六、参数
  4. <a name="Vs2RW"></a>
  5. #### 1、常见参数
  6. | **常见参数处理** | **说明** |
  7. | --- | --- |
  8. | $# | 传递到脚本的参数个数 |
  9. | $* | 以一个单字符串显示所有向脚本传递的参数 |
  10. | $$ | 脚本运行的当前进程ID |
  11. | $! | 后台运行的最后一个进程的ID |
  12. | $@ | $*相同,但是使用时加引号,并在引号中返回每个参数 |
  13. | $_ | 显示shell使用的当前选项,与set命令功能相同 |
  14. | $? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误 |
  15. <a name="ZYydJ"></a>
  16. #### 2、脚本参数
  17. 执行shell脚本时,向脚本传递参数,脚本内获取参数的格式为:`$n`。<br />n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推......<br />`$0` 为执行的文件名。
  18. ```shell
  19. chmod +x test.sh
  20. ./test.sh 1 3 5
  1. vi test.sh
  2. echo "Shell 传递参数实例!"; ## Shell 传递参数实例!
  3. echo "执行的文件名:$0"; ## 执行的文件名:./test.sh
  4. echo "第一个参数为:$1"; ## 第一个参数为:1
  5. echo "第二个参数为:$2"; ## 第二个参数为:3
  6. echo "第三个参数为:$3"; ## 第三个参数为:5

注意:$* 与 $@ 区别
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,
则 “$*” 等价于 “1 2 3”(传递了一个参数),
而 “$@” 等价于 “1” “2” “3”(传递了三个参数)

3、函数参数

在shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值。
例如:$1 表示第一个参数,$2 表示第二个参数…

  1. funWithParam(){
  2. echo "第一个参数为 $1 !" ## 第一个参数为 1 !
  3. echo "第二个参数为 $2 !" ## 第二个参数为 2 !
  4. echo "第十个参数为 $10 !" ## 第十个参数为 10 !
  5. echo "第十个参数为 ${10} !" ## 第十个参数为 34 !
  6. echo "第十一个参数为 ${11} !" ## 第十一个参数为 73 !
  7. echo "参数总数有 $# 个!" ## 参数总数有 11 个!
  8. echo "作为一个字符串输出所有参数 $* !" ## 作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
  9. }
  10. funWithParam 1 2 3 4 5 6 7 8 9 34 73

注意: $10不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。
**

七、流程控制

1、if else 分支

  1. if 语句语法格式:

    1. if condition
    2. then
    3. command1
    4. ...
    5. commandN
    6. fi

    写成一行(适用于终端命令提示符):if [ condition ]; then command; fi

    1. if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
  2. if else 语法格式:

    1. if condition
    2. then
    3. command1
    4. ...
    5. commandN
    6. else
    7. command
    8. fi
  3. if else-if else 语法格式:

    1. if condition1
    2. then
    3. command1
    4. elif condition2
    5. then
    6. command2
    7. else
    8. commandN
    9. fi

    2、for 循环

    ```shell

    for循环一般格式为:

    for var in item1 item2 … itemN do command1 … commandN done

写成一行:

for var in item1 item2 … itemN; do command1; command2… done;

其他形式:

for((assignment;condition;next));do command_1; command_2; commond_N; done;

  1. 通常情况下shell变量调用需要加 **$ **符,但是 for 中的 (()) 中不需要。<br />与 C 中相似,赋值和下一步执行可以放到代码之前循环语句之中执行,这里要注意一点:如果要在循环体中进行 for 中的 next 操作,记得变量要加 **$**,不然程序会变成死循环。
  2. <a name="zAlox"></a>
  3. #### 3、while 语句
  4. while循环用于不断执行一系列命令,也用于从输入文件中读取数据、读取键盘信息;命令通常为测试条件。其格式为:
  5. ```shell
  6. while condition
  7. do
  8. command
  9. done

4、无限循环

  1. ## 无限循环语法格式:
  2. while :
  3. do
  4. command
  5. done
  6. ## 或者:
  7. while true
  8. do
  9. command
  10. done
  11. ## 或者:
  12. for (( ; ; ))

5、until 循环

until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

  1. until condition
  2. do
  3. command
  4. done

condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。

6、case 语句

case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

  1. case in
  2. 模式1)
  3. command1
  4. ...
  5. commandN
  6. ;;
  7. 模式2)
  8. command1
  9. ...
  10. commandN
  11. ;;
  12. *)
  13. command1
  14. ...
  15. ;;
  16. esac

esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 ***** 捕获该值,再执行后面的命令。

7、跳出循环

break命令:允许跳出所有循环(终止执行后面的所有循环)
continue命令:与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环

八、输入/输出重定向

1、重定向命令列表

命令 说明
command > file 将输出重定向到 file 覆盖
command >> file 将输出以追加的方式重定向到 file
command < file 将输入重定向到 file
n > file 将文件描述符为 n 的文件重定向到 file
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file
n >& m 将输出文件 m 和 n 合并
n <& m 将输入文件 m 和 n 合并
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入

默认情况下,command > file 将stdout 重定向到 file,command < file 将stdin 重定向到 file。 需要注意的是: 文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。

2、操作示例

  1. stderr 重定向到 file

    1. command 2 > file # stderr 重定向到 file
    2. command 2 >> file # stderr 追加到 file 文件末尾
  2. stdout 和 stderr 合并后重定向到 file

    1. command > file 2>&1
    2. command >> file 2>&1
  3. 对 stdin 和 stdout 都重定向

    1. command < file1 > file2
    2. # command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。
    3. # 即command,从文件file1读取内容,然后将输出写入到file2中。
  4. /dev/null 文件 ```shell

    /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。

    但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到”禁止输出”的效果。

    如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。

    command > /dev/null

如果希望屏蔽 stdout 和 stderr,可以这样写

command > /dev/null 2>&1

  1. > **注意:这里的 2 > 之间不可以有空格,2> 是一体的时候才表示错误输出。**
  2. 5. << tag 的使用
  3. ```shell
  4. ## 基本形式如下:
  5. command << delimiter
  6. document
  7. delimiter
  8. ## 它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。

注意:

  • 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
  • 开始的delimiter前后的空格会被忽略掉。
  1. ## 在命令行中通过 wc -l 命令计算输入的行数
  2. wc -l << EOF
  3. demo1
  4. demo2
  5. demo3333
  6. EOF
  7. ## 输出结果为3

九、shell 文件包含

shell可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。

  1. ## shell 文件包含的语法格式如下:
  2. . filename # 注意点号(.)和文件名中间有一空格
  3. ## 或者
  4. source filename

十、常见的shell命令