Shell脚本基础
Kernel
Linux内核主要是为了和硬件交互
Shell
命令解释器
Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁,Shell既是一种命令语言,也是一种程序设计语言
Shell是指一种应用程序,这个应用提供了一个界面,用户通过这个界面访问操作系统内核的服务
声明
#!
声明,告诉系统其后路径所指定的程序即是解释此脚本文件的Shell程序
#!/bin/bash
echo "Hello world!"
运行sh脚本的几种方式
./hello.sh
/root/hello.sh #绝对路径,必须是可执行文件
sh hello.sh #普通文件,脚本文件都可以
source hello.sh #与前面的不同,不会重新打开一个进程运行脚本,基于当前bash运行脚本
export
变量的引用顺序为:从当前进程查询变量,如果当前进程没有这个变量,则从父进程查询这个变量
如果使用export修饰变量,那么这个变量对于子进程就是可见的
变量
变量定义规则
定义变量时,变量名不加$
- 命名只能使用英文字母,数字和下划线,首字符不能以数字开头
- 中间不能有空格
- 不能使用bash关键字(help可以查看保留关键字)
注意等号两侧避免使用空格
变量类型
- 局部变量
- 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其它shell启动的程序不能访问局部变量
- 环境变量
- 所有程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行
- Shell变量
- shell变量是由shell程序设置的特殊变量,shell变量中有一部分是环境变量,有一部分是局部变量
#变量的声明
name1="bob"
name2='zhang san'
#赋值
name3=$name1
echo $name3 #bob
字符串变量
- 单引号
- 单引号里的任何字符都会照样输出,单引号中字符串中的变量是无效的
- 单引号字符串中不能出现单独一个的单引号,但可以成对出现,作为字符串拼接使用
- 双引号
- 双引号里可以有变量
- 双引号里可以出现转义字符
b=6
name=bob
echo 'a$b' #a$b
echo "a$b" #a6
#字符串拼接
echo 'My name is' $name '.' # My name is bob .
#定义字符串
str='abcdefg'
#截取字符串,代表从索引1开始截取3位
echo ${str:1:3} #bcd
数组
bash支持一维数组(不支持多维数组),并没有限定数组的大小
数组下标由0开始编号,获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于0
#定义一个数组,不同元素用空格分隔
fav=("唱" "跳" "RAP" "篮球")
#取数组中的值,下标取值,从0开始
echo ${fav[0]} #唱
#获取数组所有元素
echo ${fav[@]} #唱 跳 RAP 篮球
#也可以使用数字下标来定义数组
fav[4]="游泳"
echo ${fav[4]}
运算符
算术运算符
直接使用运算符是无效的,如echo $a+$b
只会显示1+2
这样的结果
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,这里使用expr
来运算
a=1
b=2
echo $a+$b #1+2
echo `expr $a+$b` #3
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | expr $a + $b 结果为 30。 |
- | 减法 | expr $a - $b 结果为 -10。 |
\* | 乘法 | expr $a \* $b 结果为 200。 |
/ | 除法 | expr $b / $a 结果为 2。 |
% | 取余 | expr $b % $a 结果为 0。 |
= | 赋值 | a=$b 把变量 b 的值赋给 a。 |
== | 相等。用于比较两个数字,相同则返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比较两个数字,不相同则返回 true。 | [ $a != $b ] 返回 true。 |
[ ]
命令是Shell脚本中进行条件判断的基础工具之一
注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 **[ $a == $b ]**。
乘号(*)前边必须加反斜杠()才能实现乘法运算;
如果使用 $(())
则可以直接用运算符,效果和expr相同
使用a=${b}的效果和a=$b也是等价的
例如
a=10
b=20
echo $((a*b))
a=10
b=20
if [ $a == $b ]
then
echo "a等于b"
fi
if [ $a != $b ]
then
echo "a不等于b"
fi
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
a=10
b=20
if [ $a -eq $b ]
then
echo "a等于b"
else
echo "a不等于b"
fi
if [ $a -lt $b ]
then
echo "a小于b"
fi
如果使用 ((…)) 作为判断语句,大于和小于可以直接使用 > 和 **<**。
if (( a > b )); then
...
fi
布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
!
(非运算符)的优先级最高。-a
(与运算符)的优先级次之。-o
(或运算符)的优先级最低
可以通过加()的方式改变运算优先级
例如
if [ ! -f "$file" ] -o ([ -d "$dir" ] -a [ -w "$dir" ]); then
echo "File does not exist or (directory exists and is writable)."
fi
逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 || $b -gt 100 ]] 返回 true |
注意:逻辑运算是用在[[]]
中的而布尔运算用在[]
中,用法和之前的布尔运算符类似
补充知识点
在Shell脚本中,[ ]
(方括号)和[[ ]]
(双方括号)都用于条件测试,但它们之间存在一些重要的区别:
[ ]
(方括号)
- 兼容性:
[ ]
是 POSIX 标准的一部分,因此在所有遵循 POSIX 的 Shell 中都可用,包括sh
、bash
、ksh
等。 - 语法限制:
[ ]
的语法较为简单,不支持复杂的字符串操作和模式匹配。 - 退出状态:
[ ]
命令执行完毕后会返回一个退出状态(0表示真,非0表示假)。 - 错误处理:如果
[ ]
内的表达式语法错误,它会产生一个非零退出状态,但不会报错。 - 使用
test
命令:在某些系统中,[ ]
实际上是一个名为test
的命令的链接,因此也可以写作test condition
。
[[ ]]
(双方括号)
- Bash 扩展:
[[ ]]
是 Bash 的扩展测试命令,提供了更多的功能和灵活性,但不是 POSIX 标准的一部分。因此,它只在支持 Bash 扩展的 Shell 中可用。 - 字符串操作:
[[ ]]
支持使用==
和!=
进行字符串比较,而[ ]
只能使用=
和!=
。 - 模式匹配:
[[ ]]
支持使用 Shell 的模式匹配符号(如*
、?
、[...]
)进行字符串匹配。 - 正则表达式:
[[ ]]
支持使用=~
进行正则表达式匹配。 - 优先级:在
[[ ]]
中,逻辑运算符&&
和||
的优先级高于比较运算符,而在[ ]
中,所有运算符的优先级是相同的。 - 错误处理:如果
[[ ]]
内的表达式语法错误,Bash 会报错并显示错误信息。 - 退出状态:与
[ ]
类似,[[ ]]
命令执行完毕后也会返回一个退出状态。
字符串运算符
下表列出了常用的字符串运算符,假定变量 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。 |
a='hello'
b='world'
if [ $a = $b ]
then
echo 'a = b'
fi
if [ $a != $b ]
then
echo 'a != b'
fi
if [ -z $a ]
then
echo '字符串a长度为0'
fi
if [ -n $a ]
then
echo '字符串a长度不为0'
fi
if [ $a ]
then
echo '字符串不为空'
fi
文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。
属性检测描述如下:
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] 返回 false。 |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] 返回 false。 |
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] 返回 false。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] 返回 false。 |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] 返回 false。 |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ] 返回 false。 |
-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。 |
其他检查符:
- -S: 判断某文件是否 socket。
- -L: 检测文件是否存在并且是一个符号链接。
流程控制
if
if condition1
then
command1
elif condition2
then
command2
else
command3
fi
case
echo '输入 1 到 4 之间的数字:'
read num
case $num in
1) echo '你选择了1'
;;
2) echo '你选择了2'
;;
3) echo '你选择了3'
;;
4) echo '你选择了4'
;;
*) echo '你没有输入1到4之间的数字'
;;
esac
for
for循环使用变量名获取列表中的当前取值
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
while
while 循环用于不断执行一系列命令,也用于从输入文件中读取数据。其语法格式为:
#!/bin/bash
i=1
while(( $i<=5 ))
do
echo $i
let "i++"
done
let是用于实现类似c++中自增1的命令
break和continue
#!/bin/bash
i=1
while(( $i<=5 ))
do
echo $i
let "i++"
if (( $i>=3 ))
then
break
fi
done
continue用于跳过本次循环,break用于退出循环
函数
函数通过$1,$2来接受传参,如果超过10个参数则使用${10}这样来接受第十个参数,调用完函数后使用$?
来获取上一个函数的返回值
注意:$?取值不能超过255,否则会取其模上256
func(){
a=$1
b=$2
result=1
i=0
while (( i<b ))
do
result=$((result*a))
((i++))
done
echo "return is $result"
return $result
}
#调用函数
func 2 3
echo "func 2 3运算结果为 $?"
return is 8
func 2 3运算结果为8
exit关键字用于返回状态码,如果成功则返回0,失败返回其它状态码
另外,还有几个特殊字符用来处理参数:
参数处理 | 说明 |
---|---|
$# | 传递到脚本或函数的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
案例
func(){
timeout=5
success=0
#失败次数
fails=0
while true
do
wget www.baidu.com --timeout=${timeout} --tries=1 -q -O /etc/null
if [ $? -ne 0 ]
then
let fails=fails+1
else
let success++
fi
if ((success >= 1))
then
echo "恭喜你,该网站正在健康运作"
break
fi
if ((fails >= 2))
then
echo "该网站出现了异常"
break
fi
done
return
}
func
exit 0
检查网站是否健康的一个简单shell脚本
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com