Linux - 3. Shell编程

Shell 编程

1. HelloWorld

1.1. 第一个 Shell 脚本

创建一个 Shell 脚本,输出“hello world!”。内容如下:

#!/bin/bash 
echo "hello world!"  # echo 用于输出

#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash
注释
# 开头的行就是注释,会被解释器忽略。
多行注释

:<<EOF
注释内容...
注释内容...
注释内容...
EOF

EOF 也可以使用其他符号:
:<<'
注释内容...
注释内容...
注释内容...
'

:<<!
注释内容...
注释内容...
注释内容...
!

1.2. 执行 Shell 脚本

Shell 脚本后缀为 .sh;
脚本名称一般使用英文,表示脚本功能,单词使用下划线连接;
脚本名称不能使用特殊符号、空格、纯数字。

1.2.1. 方式一:作为可执行程序

将上面的代码保存为 hello.sh,并 cd 到相应目录:

  1. 脚本需要有可执行权限,赋予权限:chmod 744 hello.sh
  2. 执行脚本:./hello.sh

**注意:**一定要写成 ./hello.sh,而不是 hello.sh,运行其它二进制的程序也一样,直接写 hello.sh,linux 系统会去 PATH 里寻找有没有叫 hello.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 hello.sh 是会找不到命令的,要用 ./test.sh 告诉系统,就在当前目录找。

1.2.2. 方式二:作为解释器参数

直接运行解释器,其参数就是 shell 脚本的文件名,如:sh 脚本的绝对路径或相对路径
这种方式运行的脚本,不需要在第一行指定解释器信息,也不需要赋予脚本执行权限。(不推荐)


image.png

2. 变量

2.1. 定义变量

基本语法:变量名=变量值
注意:等号左右不能由空格!
变量命名规则:

  • 命名只能使用英文字母数字下划线,且不能以数字开头
  • 不能使用关键字;
  • 一般为大写(此为规范,非规则)。

2.2. 使用变量

使用变量即取变量值
基本语法:$变量名${变量名}
说明:变量名外面的花括号是可选的,加花括号是为了帮助解释器识别变量的边界。推荐给所有变量加上花括号,这是个好的编程习惯。

2.3. 删除变量

基本语法:unset 变量名
说明:变量被删除后不能再次使用。

2.4. 只读变量

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

2.5. 命令替换

命令替换是指将命令返回值赋给变量。
基本语法:变量名=命令`` 或 变量名=$(命令)
说明:$() 仅在 Bash Shell 中有效,而````可在多种 Shell 中使用。

MY_DATE=`date`
RESULT=`ls -l /home`

2.6. 作用域

根据作用域划分,Shell 变量可以分为:局部变量、全局变量、环境变量。

2.6.1. 局部变量

只能在函数内部使用的变量称为局部变量(local variable)。
Shell 函数中定义的变量默认也是全局变量,需要使用local关键字进行修饰,具体可见 9. 函数 。

2.6.2. 全局变量

只能在当前 Shell 进程的变量称为全局变量(global variable)。
在 Shell 中定义的变量,默认就是全局变量。

2.6.3. 环境变量

除了在当前 Shell 进程,还可以在子进程使用的变量称为环境变量(environment variable)。
变量需要使用export导出才是环境变量,不然子进程无法使用,如下所示。

export 变量名=变量值
# 或
变量名=变量值
export 变量名
xmh@xmh:~$ a=22       #定义一个全局变量
xmh@xmh:~$ echo $a    #在当前Shell中输出a,成功
22
xmh@xmh:~$ bash       #进入Shell子进程
xmh@xmh:~$ echo $a    #在子进程中输出a,失败

xmh@xmh:~$ exit       #退出Shell子进程,返回上一级Shell
exit
xmh@xmh:~$ export a   #将a导出为环境变量
xmh@xmh:~$ bash       #重新进入Shell子进程
xmh@xmh:~$ echo $a    #在子进程中再次输出a,成功
22
xmh@xmh:~$ exit       #退出Shell子进程
exit
xmh@xmh:~$ exit       #退出父进程,结束整个Shell会话

注意:

  1. 两个没有父子关系的 Shell 进程是不能传递环境变量的,并且环境变量只能向下传递而不能向上传递,即“传子不传父”。
  2. 通过export导出的环境变量只对当前 Shell 进程以及所有的子进程有效,如果最顶层的父进程被关闭了,那么环境变量也就随之消失了,其它的进程也就无法使用了,所以说环境变量也是临时的。
  3. 如果希望环境变量在所有 Shell 进程中都有效,需要将变量写入 Shell 配置文件中才能达到这个目的!Shell 进程每次启动时都会执行配置文件中的代码做一些初始化工作,如果将变量放在配置文件中,那么每次启动进程都会定义这个变量。在 Linux 中,内置了一些环境变量,可以使用 env 命令可以显示所有环境变量。
    1. PATH:命令搜索路径
    2. USER:当前用户
    3. HOME:当前用户的主目录
    4. SHELL:当前使用的 Shell
    5. UID:当前用户的 UID
    6. HOSTNAME:主机名
    7. TERM:当前使用的终端类型
    8. PWD:当前工作路径

3. 特殊变量

特殊变量是 shell 官方已经定义好的变量,可以直接在 shell 脚本中使用。特殊变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。
特殊变量有以下几种:

  • 特殊状态变量
  • 特殊位置变量
  • 特殊扩展变量

3.1. 特殊状态变量

  1. $$ :当前执行Shell脚本的进程的进程号(PID)。
  2. $! :上一个后台运行的进程的进程号(PID)。
  3. $? :上一个命令的执行状态返回值(0成功,非0为失败)。具体细节如下:
    • 判断命令、脚本或者函数等程序是否执行成功。
    • 在脚本中调用执行exit 数字,会返回这个数字给 $? 变量。
    • 在函数中,会通过return 数字,把数字以函数返回值的形式传给 $?
  4. $_:在此之前执行的命令或脚本的最后一个参数。

3.2. 特殊位置变量

  1. $0:当前执行的 Shell 脚本文件名,如果执行脚本时候加了路径,那就包含路径路径跟脚本文件名一起输出。
  2. $n:当前执行的Shell脚本或函数的第 n 个参数。$1- 9 代表第 1 个到第 9 个参数,后面的参数表示时需用 ‘ ‘ 包裹,如 ‘ 9 代表第1个到第9个参数,后面的参数表示时需用`{}`包裹,如` 9代表第1个到第9个参数,后面的参数表示时需用包裹,如{10}` 。可由此传递参数。
  3. $#:当前执行的Shell脚本或函数接收参数的个数。
  4. $*:当前执行的Shell脚本或函数接收的所有参数,**$***** 把所有的参数看成一个整体,此变量是一个数组。**
  5. $@:当前执行的Shell脚本或函数接收的所有参数,**$@**** 把每个参数区分对待,此变量是一个数组。**

3.3. 特殊扩展变量

  1. ${parameter:-word}:如果 parameter 的变量值为空或者未赋值,则返回 word 字符串并代替变量的值(防止变量为空或没定义报错)
  2. ${parameter:=word}:同上
  3. ${parameter:?word}:如果 parameter 的变量值为空或者未赋值,则 word 字符串就作为标准错误输出(捕捉由于变量未定义导致的错误,并退出)
  4. ${parameter:+word}:如果 parameter 不为空或者未赋值,则使用 word 字符串将代替变量的值,否则什么也不做。

4. 字符串

字符串有两种定义方式,用单引号 '' 或 双引号 "" 定义。

4.1. 单引号

  • 单引号中所有的字符都会原样输出,也就是说单引号中的变量是无效的。
  • 单引号中不能再出现单引号(对单引号转义符也无效),但可成对出现,作为字符串拼接使用

4.2. 双引号

  • 双引号中可以有变量。
  • 可以使用转义符。
STR='test line'
echo 'It is a ${STR}'  # 输出:It is a ${STR}
echo "It is a \"${STR}\""  # 输出:It is a "test line"

4.3. 操作字符串

4.3.1. 拼接字符串
  1. 双引号字符串拼接
STR='test line'

# 方式一:使用双引号
echo "It is a "test line""  # 输出:It is a test line
echo "It is a "${STR}""  # 输出:It is a test line

# 方式二:引用变量
echo "It is a ${STR}"  # 输出:It is a test line
  1. 单引号字符串拼接
STR='test line'
# 只能使用单引号拼接
echo 'It is a '${STR}''  # 输出:It is a test line
4.3.2. 获取字符串长度

基本语法:${#变量名}

STR='test line'
echo ${#STR}  # 输出:9
4.3.3. 提取子字符串

基本语法:${变量名:起始索引:结束索引}
注:第一个字符索引值为 0 。

STR='test line'
echo ${STR:1:3}  # 输出:est
4.3.4. 使用 expr 操作字符串

expr是 evaluate expressions 的缩写,译为“表达式求值”。使用expr操作字符串,索引从 1 开始。

  1. 获取字符串长度:expr length 字符串
  2. 提取子字符串:expr substr 字符串 起始位置 结束位置
  3. 获取某字符在字符串中首次出现位置(依次寻找字符序列中的字符,返回先找到的字符位子):expr index 字符串 字符序列
  4. 模式匹配(正则表达式默认带有^;成功返回匹配字符长度,否则为 0):expr match 字符串 正则表达式
  5. 模式匹配(正则表达式默认带有^;成功返回匹配字符长度,否则为 0):expr 字符串 : 正则表达式
str="you are the best"

expr length "$str"
16

expr substr "$str" 13 16
best

expr index "$str" vut
3

expr match "$str" ".*a"
5

5. 数组

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

5.1. 定义数组

基本语法:

  • 数组名=(值1 值2 ... 值n)
  • 数组名[索引值]=元素值
# 形式一:
ARR1=("ARR1_first" "ARR1_second" "ARR1_third")
# 形式二:
ARR2=(
"ARR2_first"
"ARR2_second"
"ARR2_third"
)
# 形式三:
ARR3[0]="ARR3_first"
ARR3[1]="ARR3_second"
ARR3[9]="ARR3_tenth"

5.2. 读取数组

基本语法:${数组名[下标]}
注:${数组名[@]}${数组名[*]} 可以获取数组的所有元素值

echo ${ARR1[0]}
echo ${ARR1[@]}

echo ${ARR2[0]}
echo ${ARR2[@]}

echo ${ARR3[0]}
echo ${ARR3[4]}
echo ${ARR3[9]}
echo ${ARR3[@]}

# 输出
ARR1_first
ARR1_first ARR1_second ARR1_third
ARR2_first
ARR2_first ARR2_second ARR2_third
ARR3_first

ARR3_tenth
ARR3_first ARR3_second ARR3_tenth

5.3. 获取元信息

  • 取得数组元素的个数:${#数组名[@]}
  • 取得数组元素的个数:${#数组名[*]}
  • 取得数组单个元素的长度:${#数组名[索引值]}

6. 数学表达式

6.1. 算术运算符

加减乘除等

  • +:加法(正号)
  • -:减法(负号)
  • *:乘法
  • /:除法
  • %:取余(取模)
  • **:幂运算
  • ++:自增
  • --:自减

比较

  • ==:相等。用于比较两个数字,相同则返回 true。
  • !=:不相等。用于比较两个数字,不相同则返回 true。
  • <:小于
  • <=:小于等于
  • >:大于
  • >=:大于等于

赋值

  • =
  • +=
  • -=
  • *=
  • /=
  • %=

位运算

  • <<:向左移位
  • >>:向右移位
  • ~:按位取反
  • |:按位或
  • &:按位与
  • ^:按位异或

6.2. 逻辑运算符

  • &&:逻辑与
  • ||:逻辑或
  • !:逻辑非

6.3. 命令

在 Shell 中,每一个变量的值都是字符串,无论给变量赋值时带不带引号,变量之都会以字符串的形式存储。因此要进行数学计算,需要使用数学计算命令。

6.3.1. (())

(()) 是 bash 中专门进行整数运算(只能进行整数运算,不能对浮点数或者字符串进行运算)的命令,效率高,写法灵活。

  • 基本语法:((数学表达式))
  • (())中的表达式可以有 1 个或多个,多个表达式使用逗号,分割。对于多个表达式的情况,以最后一个表达式的值作为整个(())命令的执行结果。
  • (())中使用变量无需加上$前缀,(())会自动解析变量名。
  • (())前面加上$符号获取命令的执行结果。
  • (())也可以进行逻辑运算。
xmh@WSL:~$ ((a=10+5))
xmh@WSL:~$ echo $a
15
xmh@WSL:~$ ((b=10+1,c=10+2))
xmh@WSL:~$ echo $((b=10+1,c=10+2))
12
xmh@WSL:~$ echo $((c=a+b))
26
xmh@WSL:~$ echo $((a==b && b==c))
0
xmh@WSL:~$ echo $((a++))
15
xmh@WSL:~$ echo $((++a))
17
6.3.2. let

let只能进行整数运算(只能进行整数运算,不能对浮点数或者字符串进行运算)。

  • 基本语法:let 数学表达式 或者 let "数学表达式" 或者 let "数学表达式"
  • 当表达式中含有 Shell 特殊字符(例如|)时,需要用双引号""或者单引号''将表达式包围起来。
  • let中的表达式可以有 1 个或多个,多个表达式使用逗号空格分割。
  • let中使用变量无需加上$前缀,let会自动解析变量名。
  • let命令会将计算结果丢弃,需要使用变量在let中接收结果。
  • let支持逻辑运算。
xmh@WSL:~$ let a=10+5
xmh@WSL:~$ echo $a
15
xmh@WSL:~$ let b=a+1 c=a+2
xmh@WSL:~$ echo $b
16
xmh@WSL:~$ echo $c
17
xmh@WSL:~$ let d=a++
xmh@WSL:~$ echo $d
15
xmh@WSL:~$ let "e=(15==15&&16==16)"
xmh@WSL:~$ echo $e
1
6.3.3. $[]

$[]只能进行整数运算。

  • 基础语法:$[数学表达式]
  • $[]只支持 1 个表达式,不能有多个表达式。
  • $[]使用变量时,可加$,也可以不加。
  • 不能单独使用$[],必须接收其计算结果。
  • $[]支持逻辑运算。
xmh@WSL:~$ $[5+6]
11: command not found
xmh@WSL:~$ echo $[5+6]
11
xmh@WSL:~$ echo $[5==6]
0
xmh@WSL:~$ echo $[5==6||6==6]
1
6.3.4. expr
  • 基本语法:expr 数学表达式
  • 只能计算 1 个表达式。
  • 出现在表达式中的运算符、数字、变量和小括号的左右两边至少要有一个空格,否则会报错。
  • 有些特殊符号必须用反斜杠\进行转义,比如乘号*和小括号(),如果不用\转义,那么 Shell 会把它们误解为正则表达式中的符号(*对应通配符,()对应分组)。
  • 使用变量时要加$前缀。
  • 只支持+ - * / % > >= != = <= < & |
xu_menghao@WSL:~$ expr 2 + 3
5
xu_menghao@WSL:~$ expr 4 * 5
expr: syntax error: unexpected argument ‘test’
xu_menghao@WSL:~$ expr 4 \* 5
20
xu_menghao@WSL:~$ expr 4 / 2
2
xu_menghao@WSL:~$ expr 4 - 2
2
xu_menghao@WSL:~$ expr 4 \* \( 2 + 5 \)
28
6.3.5. bc

Linux 下的一个计算器程序,可以处理整数和浮点数。
Linux bc命令:一款数学计算器

6.3.6. declare -i

使用declare -i将变量定义为整数,然后再进行数学运算。

  • 仅支持最基本的数学运算:加减乘除和取余,不支持逻辑运算、自增自减等。
  • 除了将参与运算的变量定义为整数,还得将承载结果的变量定义为整数,而且只能用整数类型的变量来承载运算结果,不能直接使用echo输出。
declare -i m n ret
m=10
n=30

ret=$m+$n
echo $ret
40

ret=$n/$m
echo $ret
3

7. 条件表达式

7.1. test 与 [

在 Shell 中,可以使用内置命令test[处理条件表达式。[test的近似命令,只有一处不同,**[**需要以**]**作为参数结尾以匹配**[**,因此**[**命令在形式上如下所示:**[ 条件表达式 ]****。**所以只需要会test,同样就会使用[

test命令、[命令提供四类操作符:关系操作符、字符串操作符、文件操作符、其他操作符。

test命令、[命令对条件表达式求值,如果求值为true,则返回 0,如果求值为false或给出无效参数,则返回 1 。

7.1.1. 关系操作符

关系操作符只支持数字,不支持字符串,除非字符串的字面量是数字。

  • ARG1 -eq ARG2:如果两个数相等,则为 true。
  • ARG1 -ne ARG2:如果两个数不相等,则为 true。
  • ARG1 -gt ARG2:如果 ARG1 大于 ARG2 ,则为 true。
  • ARG1 -lt ARG2:如果 ARG1 小于 ARG2 ,则为 true。
  • ARG1 -ge ARG2:如果 ARG1 大于等于 ARG2 ,则为 true。
  • ARG1 -le ARG2:如果 ARG1 小于等于 ARG2 ,则为 true。
7.1.2. 字符串操作符
  • STRING1 = STRING2:如果两个字符串相等,则为 true。
  • STRING1 != STRING2:如果两个字符串不相等,则为 true。
  • STRING1 < STRING2:如果 STRING1 按字典顺序排在 STRING2 之前,则为 true。
  • STRING1 > STRING2:如果 STRING1 按字典顺序排在 STRING2 之后,则为 true。
  • -z STRING:如果字符串长度为 0,则为 true。
  • -n STRING:如果字符串长度不为 0,则为 true。

注意:使用><需要使用\转义。

7.1.3. 文件操作符

用于检测文件的各种属性。如果 FILE 是软链接,则除-h-L之外的所有文件操作符都作用于软链接的目标,而不是软链接本身。

  • -a FILE:如果文件存在,则为 true。
  • -b FILE:如果文件是块设备文件,则为 true。
  • -c FILE:如果文件是字符设备文件,则为 true。
  • -d FILE:如果文件是目录,则为 true。
  • -e FILE:如果文件(包括目录)存在,则为 true。
  • -f FILE:如果文件是普通文件(既不是目录,也不是设备文件),则为 true。
  • -g FILE:如果文件设置了 SGID 位,则为 true。
  • -h FILE:如果文件存在并且是一个符号链接,则为 true。
  • -L FILE:如果文件存在并且是一个符号链接,则为 true。
  • -k FILE:如果文件设置了粘着位(Sticky Bit),则为 true。
  • -p FILE:如果文件是有名管道,则为 true。
  • -r FILE:如果文件可读,则为 true。
  • -s FILE:如果文件不为空(文件大小大于0),则为 true。
  • -S FILE:如果文件是 socket,则为 ture。
  • -t FD:如果在终端上打开 FD,则为 true.
  • -u FILE:如果文件设置了 SUID 位,则为 true。
  • -w FILE:如果文件可写,则为 true。
  • -x FILE:如果文件可执行,则为 true。
  • -O FILE:如果该文件实际上为你所有,则为 true。
  • -G FILE:如果该文件实际上为你的用户组所有,则为 true。
  • -N FILE:如果文件自上次读取以来已被修改,则为 true。
  • FILE1 -nt FILE2:如果 FILE1 比 FILE2 更新(根据修改日期),则为 true。
  • FILE1 -ot FILE2:如果 FILE1 比 FILE2 更老(根据修改日期),则为 true。
  • FILE1 -ef FILE2:如果 FILE1 是到 FILE2 的硬链接,则为 true。
7.1.4. 其他操作符
  • -o OPTION:如果 Shell 选项 option 被启用,则为true。
  • -v VAR :如果设置了 Shell 变量 VAR ,则为 true。
  • -R VAR:如果设置了 Shell 变量 VAR 并且是一个名称引用,则为 true。
  • EXPR1 -a EXPR2:如果 EXPR1 和 EXPR2 都为 true 则为 true。
  • EXPR1 -o EXPR2:如果 EXPR1 或 EXPR2 为 true 则为 true。
  • ! EXPR:如果 EXPR 为 false 则为 true。

7.2. [[

[[也是内置命令,用于条件表达式求值。**[**类似,**[[**需要以**]]**作为参数结尾以匹配**[[**,因此**[[**命令在形式上如下所示:**[[ 条件表达式 ]]**

[[支持上述关系操作符、字符串操作符、文件操作符,但不支持-a-o-a功能使用&&替代,-o功能使用||替代,且&&``||分别是短路与、短路或。

[[还支持使用小括号()包裹表达式以分隔:( EXPRESSION ),会返回 EXPRESSION 的值。

[[支持更多的字符串操作。

  • 使用==!=操作符时,将操作符右侧的字符串用作模式,并执行模式匹配。
  • 使用=~操作符时,将操作符右侧的字符串作为正则表达式进行匹配。

test命令、[命令对条件表达式求值,如果求值为true,则返回 0,如果求值为false或给出无效参数,则返回 1 。

注:[[]]对数字的比较仍然不友好,因此使用if判断条件时,用(())来处理整型数字,用[[]]来处理字符串或者文件。

8. 流程控制

8.1. 分支结构

8.1.1. if-elif-else
if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi # fi 为 if 倒序

condition表示条件,一般使用第 7 节中的条件表达式,还可以使用(())。如果对应条件成立,则执行相应的语句。

#!/bin/bash

str1="abc"
str2="edf"

if [[ $str1 < $str2 ]]
then
        echo true
else
        echo false
fi
#!/bin/bash

num1=12
num2=15

if ((num1<num2))
then
        echo true
else
        echo false
fi
8.1.2. case…esac
case expression in
pattern1)
    command1
    command2
    ...
    commandN
    ;;
pattern2)
    command1
    command2
    ...
    commandN
    ;;
*)
    command1
    command2
    ...
    commandN
    ;;
esac # esac 为 case 倒序

caseinesac 都是 Shell 关键字,expression表示表达式,pattern表示匹配模式。

  • expression既可以是一个变量、一个数字、一个字符串,还可以是一个数学计算表达式,或者是命令的执行结果,只要能够得到 expression 的值就可以。
  • pattern可以是一个数字、一个字符串,甚至是一个简单的正则表达式。

case会将expression的值与pattern1pattern2逐个进行匹配:

  • 如果expression和某个模式(比如pattern2)匹配成功,就会执行此模式后面对应的所有语句(该语句可以有一条,也可以有多条),直到遇见双分号;;才停止;然后整个case语句就执行完了,程序会跳出整个case语句,执行esac后面的其它语句。
  • 如果expression没有匹配到任何一个模式,那么就执行*)后面的语句,直到遇见双分号;;或者esac才结束。*)相当于多个if分支语句中最后的else部分。最后一个分支*)并不是什么语法规定,它只是一个正则表达式,*表示任意字符串,所以不管expression的值是什么,*)总能匹配成功。没有也不会影响语句结束。

pattern部分支持简单的正则表达式,具体来说,可以使用以下几种格式:

  • *表示任意字符串。
  • [abc]表示 a、b、c 三个字符中的任意一个。比如,[15ZH] 表示 1、5、Z、H 四个字符中的任意一个。
  • [m-n]表示从 m 到 n 的任意一个字符。比如,[0-9]表示任意一个数字,[0-9a-zA-Z]表示字母或数字。
  • | 表示多重选择,类似逻辑运算中的或运算。比如,abc | xyz 表示匹配字符串 “abc” 或者 “xyz”。

如果不加以说明,Shell 的值都是字符串,expressionpattern也是按照字符串的方式来匹配的。

echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac
#!/bin/sh

site="baidu"

case "$site" in
   "baidu") echo "百度"
   ;;
   "google") echo "谷歌"
   ;;
   "bing") echo "必应"
   ;;
esac

8.2. 循环结构

8.2.1. for
# 基本语法1
for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

# 基本语法2
for var in ${数组名[*]}
do
    command1
    command2
    ...
    commandN
done

# 基本语法3
for ((i=1; i<5; i++))
do
    command1
    command2
    ...
    commandN
done
#!/bin/bash

for str in This is a string
do
    echo $str
done
#!/bin/bash

arr=("Hello" "World" "!")

for var in ${arr[*]}
do
        echo $var
done
8.2.2. while
while condition
do
    command
done

当条件满足时,while重复地执行一组语句,当条件不满足时,就退出while循环。
先对condition进行判断,如果该条件成立,就进入循环,执行while循环体中的语句,也就是dodone之间的语句。这样就完成了一次循环。
每一次执行到done的时候都会重新判断condition是否成立,如果成立,就进入下一次循环,继续执行dodone之间的语句,如果不成立,就结束整个while 循环,执行done 后面的其它代码。

8.2.3. until
until condition
do
    command
done

until循环和while循环恰好相反,当判断条件不成立时才进行循环,一旦判断条件成立,就终止循环。

8.2.4. 无限循环
# 方式一
while : 
do
	command
done
# 方式二
while true
do
	command
done
# 方式三
for (( ; ; ))
8.2.5. 跳出循环:break、continue
  • break:跳出所有循环(终止执行后面的所有循环)。
  • continue:跳出当前循环。

9. 函数

shell 编程和其它编程语言一样,有系统函数,也可以自定义函数。

9.1. 常用系统函数

9.1.1. basename

函数功能:返回完整路径最后 / 的部分,常用于获取文件名。
函数使用:basename [pathname] [suffix]
删掉所有的前缀包括最后一个 / 字符,然后将字符串显示出来。如果 suffix 被指定了,basename 会将 pathname 中的 suffix 去掉。
image.png

9.1.2. dirname

函数功能:返回完整路径最后 / 的前面的部分,常用于返回路径部分。
函数使用:dirname 文件绝对路径
从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)。
image.png

9.2. 自定义函数

[ function ] funname()
{

    action;

    [return int;]
}

说明:

  1. [] 内表示可选。
  2. return可选,后跟数字,范围为 0-255 。如果不加 return,将以最后一条命令运行结果,作为返回值。

实例:

#!/bin/bash

# 计算输入两个参数的和
function getSum(){
	SUM=$[$NUM1+$NUM2]
  echo "$SUM"
}

read -p "请输入第一个数n1" NUM1
read -p "请输入第二个数n2" NUM2

# 调用getSum并传参
getSum $Num1 $Num2

也可以这样写

#!/bin/bash

function getSum(){
	read -p "请输入第一个数n1" NUM1
	read -p "请输入第二个数n2" NUM2
	SUM=$[$NUM1+$NUM2]
  echo $SUM
}
# 调用getSum
getSum

10. 文件包含

和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。
Shell 文件包含的语法格式如下:

# 方式一
. filename   # 注意点号(.)和文件名中间有一空格 
# 方式二
source filename

创建两个 shell 脚本文件。
test1.sh 代码如下:

#!/bin/bash 
url="http://www.baidu.com"

test2.sh 代码如下

#!/bin/bash
#使用 . 号来引用test1.sh 文件
. ./test1.sh
# 或者使用以下包含文件代码
# source ./test1.sh 
echo "百度:$url"

接下来,我们为 test2.sh 添加可执行权限并执行:

$ chmod +x test2.sh
$ ./test2.sh
百度:http://www.baidu.com

注:被包含的文件 test1.sh 不需要可执行权限。


常用命令:read、echo、print、awk、sed、find、grep、eval

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值