Shell脚本的建立与执行
在子Shell中执行
当执行一个脚本文件时,Shell就会产生一个子Shell(即一个子进程)去执行命令文件中的命令。
1.将文件名作为Shell命令的参数:$bash script-file
2.现将脚本文件的权限改为可执行,然后执行脚本:$script-file
在当前Shell中执行
使用source 或 “ . ”命令执行,例如:$source script-file
Shell脚本编码规范
以#!开头,指明使用何种Shell解析脚本
例如:#!/bin/bash 或 #!/usr/bin/env bash
良好的编码过饭还要求以注释说明如下的内容:
#脚本名称
#脚本功能
#作者及联系方式
#版本更新记录
#版权声明
#对算法做简要说明
Shell变量操作
变量替换
功能 | 表达式 | 说明 |
---|---|---|
使用默认值 | ${var:-word} | 若var存在且非空,则值为$var; 若var未定义或为空值,则值为word,但var的值不变 |
赋予默认值 | ${var:=word} | 若var存在且非空,则值为$var; 若var未定义或为空值,则值为word,且var被赋值word |
使用默认值 | ${var:?word} | 若var存在且非空,则值为$var; 若var未定义或为空值,则输出word,并终止脚本 |
使用默认值 | ${var:+word} | 若var存在且非空,则值为word; 若var未定义或为空值,则返回空值,但var的值不变 |
变量字符串操作
表达式 | 说明 |
---|---|
${#var} | 返回字符串变量var的长度 |
${var:m} | 返回$var中从第m个字符到最后的部分 |
${var:m:len} | 返回$var中从第m个字符开始,长度为len的部分 |
${var#pattern} | 删除${var}中开头部分与pattern匹配的最小部分 |
${var##pattern} | 删除${var}中开头部分与pattern匹配的最大部分 |
${var%pattern} | 删除${var}中结尾部分与pattern匹配的最小部分 |
${var%%pattern} | 删除${var}中结尾部分与pattern匹配的最小部分 |
${var/old/new} | 用new替换${var}中第一次出现的old |
${var//old/new} | 用new替换${var}中所有的old |
${var/#old/new} | 用new替换${var}中开头部分的old |
${var/%old/new} | 用new替换${var}中结尾部分的old |
变量的数值计算
运算符 | 说明 |
---|---|
+、-、*、/ | 四则运算 |
**、% | 幂运算、模运算 |
++、– | 自增、自减 |
=、+=、-=、*=、/=、%= | 赋值运算符 |
<、>、<=、>=、==、!= | 比较运算 |
&&、||、! | 逻辑运算 |
let命令,expr命令,以及最先出现的C语言风格的Shell算术运算符((…))
例如:$((a=2+3**2-1001%5))
Shell变量的输入
read [-p ] <变量名>
让用户输入,-p指定提示语句
Shell特殊变量
位置参数 | 说明 |
---|---|
$0 | 脚本名称 |
$n | n是大于等于1的正数,表示n个位置的参数。当n>9时,要使用${n} 形式引用 |
$# | 位置参数的个数 |
$@、“$@” | 将每个位置参数看成单独字符串(以空格间隔) |
$* | 将所有位置参数看成一个字符串(以空格间隔) |
“$*” | 将所有位置参数看成一个字符串(以$IFS间隔) |
Shell的进程状态变量
特殊变量 | 说明 |
---|---|
$$ | 当前进程的PID |
$! | 运行在后台的最后一个作业的PID |
$? | 在此之前执行的命令或脚本的返回值,0表示成功,非0表示不同原因的失败 |
$_ | 在此之前执行的命令或脚本的最后一个参数 |
注意:每个命令都会返回一个退出状态码(也称为返回状态),0为成功,非0为不成功,非零值通常都被解释成一个错误码,在脚本中exit n命令将会把退出状态码(n)传递给父Shell(n必须是十进制数,范围是0~255)
Shell 脚本跟踪与调试
使用bash参数调试脚本
命令 | 说明 |
---|---|
bash -n < script name> | 对脚本进行语法检查,通常在执行脚本之前检查其语法是否正确 |
bash -v < script name> | 显示脚本中每个原始命令行及其执行结果 |
bash -x < script name> | 以调试模式执行脚本,对脚本中每条命令的处理过程:先执行替换,然后显示,再执行命令 |
在脚本中使用set命令调试脚本
当脚本文件较长时,可以使用set命令指定调试一段脚本。在脚本中使用set -x命令开启调试模式,使用set +x命令关闭调试模式,例如
#!/bin/bash
echo -e “Hello $LOGNAME, \c”
set -x ###开启调试模式
read -p “What is your name” name
echo “Hello $name”
set +x ###关闭调试模式
条件测试和分支结构
测试语句
格式1: test <测试表达式>
格式2: [ <测试表达式> ]
格式3: [[ <测试表达式> ]]
测试语句可以判断命令成功或失败、表达式为真或假,bash中没有布尔类型,0表示成功或真,非零表示失败或假。
注意:
1.格式1和格式2是等价的,格式3时扩展的test命令
2.在[[ ]]中可以使用Shell通配符进行模式匹配
3.&&,||,< 和>操作符能够正常的在[[ ]]中使用,但不能再[ ]中出现
4.[和[[只后的字符必须是空格,]和]]之前必须是空格
5.要读整数进行关系运算,可以使用Shell的算术运算符 (( ))进行测试
文件测试运算符
操作符 | 说明 |
---|---|
-e file | 文件是否存在 |
-f file | 是否为普通文件 |
-d file | 是否为目录 |
-L file | 是否为符号链接文件 |
-b file | 是否为块设备文件 |
-c file | 是否为字符设备文件 |
-s file | 文件长度不为0 |
-r file | 是否为只读 |
-w file | 是否为可写 |
-x file | 是否为可执行 |
-O file | 测试者是否为文件属主 |
-G file | 测试者是否为文件同组人 |
-u file | 是否为设置了SUID的文件 |
-g file | 是否为设置了SGID的文件 |
-k file | 是否为设置了黏贴位的文件 |
file1 -nt file2 | file1是否比file2新 |
file1 -ot file2 | file1是否比file2旧 |
file1 -ef file2 | file1是否与file2共用相同的i-node(链接) |
字符串测试操作符
操作符 | 说明 |
---|---|
-z string | 测试字符串是否为空串 |
-n string | 测试字符串是否为非空串 |
string == string2 | 测试两个字符串是否相同 |
string != string2 | 测试两个字符串是否不相同 |
正数二元比较操作符
操作符功能 | 相等 | 不等 | 大于 | 大于等于 | 小于 | 小于等于 |
---|---|---|---|---|---|---|
在[]中 | -eq | -ne | -gt | -ge | -lt | -le |
在(( ))中 | == | != | > | >= | < | <= |
使用逻辑操作符
操作符功能 | “与”逻辑 | “或逻辑” | “非”逻辑 |
---|---|---|---|
在[]中 | -a | -o | -! |
在(( ))中 | && | || | ! |
分支结构循环
if语句
if < condition1>
then
< commands1>
[ elif < condition2 >
then
< command2 >
.. ]
[ else
< commandn > ]
fi
注意:
1.elif语句块可以有0到多个
2.else可以为0到1个
3.条件测试可以是表达式,
4.条件测试也可以是多个命令,以最后一个命令的退出状态为其值
5.语句块可以是一条命令、多条命令,也可以是空命令“ : ”(冒号,表示该命令不做任何事,只返回一个退出状态0)
case语句
case expr in
pattern1)
commands1
;;
pattern2)
commands2
;;
...
*)
commands
;;
esac
注意:
1.表达式expr按顺序匹配每个模式,一旦匹配成功,则执行该模式后的命令,然后退出case
2.如果没有匹配到模式,则执行默认值“ *) ”后的命令
3.所有模式可以含有通配符和逻辑或“ | ”
4.除非特殊需要,否则每个命令块左右必须有一个双分号“ ;; ”,与C语言的switch中的break语句功能一致
while和until
while condition
do
commands
done
当条件测试condition为真时执行循环体,否则退出循环
until condition
do
commands
done
当条件测试condition为真时结束循环,否则执行循环体
注意:bash提供了两个循环控制语句
break:跳出循环
continue:跳出本次循环
for语句
foreach型循环
for variable in list
do
commands
done
先将列表list的变量依次赋给variable执行commands,
C语言型循环
for (( exp1;exp2;exp3 ))
do
commands
done
首先执行依次exp1(只执行一次),执行exp2,为真时,执行commands,在执行exp3,进入下一次循环,为假时退出循环,
seq语句与大括号表达式
语法 | 举例 | 说明 |
---|---|---|
seq n | seq 10 | 生成序列[1…n],步长为1 |
seq m n | seq 0 10 | 生成序列[m…n],步长为1 |
seq m s n | seq 10 3 20 | 生成序列[m…n],步长为s |
{m…n} | {1…10}、{a…h} {10…1}、{h…a} |
生成序列[m…n]、[a…h],若m>n步长为1<br>生成序列[m…n]、[a…h],若m<n步长为-1 |
{m…n…s} | {1…10…3}、{a…h…3} {10…1…3}、{h…a…3} |
生成序列[m…n]、[a…h],若m>n步长为s<br>生成序列[m…n]、[a…h],若m<n步长为-s |
注意:
1.大括号表达式能生成字符序列,seq不能
2.大括号表达式能生成倒序,seq不能
select语句
select variable in list
do
commands
done
与for的foreach类似,但是会在菜单项之前添加一个从1开始的序号依次呈现给用户,序号存在变量RELAY中。
注意:
1.list列表的菜单项间隔符由环境变量IFS决定
2.按数值顺序排列的菜单会显示到标准错误输出
3.用户直接按键将重新显示菜单
4.与for循环类似,省略in list时等价于in “$*”
5.select是个无限循环,通常要配合case语句处理不同的选单及退出。可以使用break退出循环,或exit终止脚本
函数
函数定义
[function] name() {
commands;
}
function可以省略
注意:函数和调用它的主文件可以保持在同一个文件中,函数定义必须出现在调用之前。
函数的执行方法
name 参数1 参数2 参数n
注意:
1.调用函数时,使用位置参数的形式传递参数
2.函数内的$1-$[n]、$*和$@表示其接收的参数
3.函数调用结束后位置参数$1-$[n]、$*和$@将被重置为调用函数之前的值
4.在主程序和函数中,$0始终代表脚本名