目录
一、Shell概述
二、输入输出
三、分支控制
1. 表达式
2. if 分支
3. case 分支
四、循环控制
1. for 循环
2. while 循环
3. select 循环
五、函数
一、Shell概述
Shell是Linux系统连接用户和操作系统的外壳程序,将用户的输入和请求选择性传递给操作系统,然后处理来自操作系统的结果输出,简单来说Shell就是一个用户和操作系统之间的命令解释器。
Shell是一个外壳程序,同时也是一个脚本语言。
Shell脚本本质上是Linux命令,一条一条命令组合在一起,实现某一个功能,就形成了Shell脚本。
最常用的Shell是Bash(/bin/bash),是大多数Linux系统默认的Shell环境。
shell编程注意事项:
- shell文件通常以后缀 .sh 结尾;
- 不能使用特殊符号,有严格的空格控制;
- shell文件以 #!/bin/bash 开头
- shell脚本变量命名规则与C语言一样
二、输入输出
Shell脚本语言只有一种数据类型,就是字符类型,即所有变量的类型都是字符,输入和输出的都是字符。
Shell变量分为用户变量、环境变量、系统变量,环境变量分为用户级、系统级和脚本级,用户级变量重启Shell外壳就会自动清除,系统变量用于实现某一个功能而存在。
变量的可用 = 进行赋值创建,用 $ 获取变量值,用 unset 清除变量。
# Shell常见的环境变量:PATH 命令所示路径,以冒号为分割;
HOME 打印用户家目录;
SHELL 显示当前Shell类型;
USER 打印当前用户名;
ID 打印当前用户id信息;
PWD 显示当前所在路径;
TERM 打印当前终端类型;
HOSTNAME 显示当前主机名;
PS1 定义主机命令提示符的;
HISTSIZE 历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间;
RANDOM 随机生成一个 0 至 32767 的整数;
HOSTNAME 主机名
# Shell常见的系统变量:$0 当前脚本的名称;
$n 当前脚本的第n个参数,n=1,2,…9;
$* 当前脚本的所有参数(不包括程序本身);
$# 当前脚本的参数个数(不包括程序本身);
$? 令或程序执行完后的状态,返回0表示执行成功;
$$ 程序本身的PID号。
变量也可通过 read 进行键盘输入赋值,通过 echo 输出。
在使用 read 输入数据时,可配合 echo 使用进行输出提示,如 echo 提示字符串; read 变量 ,也可直接使用 read -p 提示字符串 变量 进行输入提示。
在用 $ 对变量取值时,为了其他字符串对变量的影响,可用 { } 跟在 $ 后面将变量括起来。
#!/bin/bash# 颜色输出格式 echo -e "\033[(显示方式);(字体色);(背景色)m(输入内容)\033[0m"
testStr1="hello world!\n"
echo $testStr1# 显示方式:
# 1 粗体高亮
# 4 下划线
# 5 闪烁
# 8 隐藏# 字体颜色:
# 31 红色
# 32 绿色
# 33 黄色
# 34 蓝色
# 35 紫色
# 36 天蓝
# 37 白色# 背景颜色:
# 41 红色
# 42 绿色
# 43 黄色
# 44 蓝色
# 45 紫色
# 46 天蓝
# 47 白色echo "请输入一个测试字符串:"; read testStr2
echo -e "\033[1;31;46m$testStr2\033[0m"
# 最后的0表示恢复默认系统输出默认设置# echo 加上 -e 选项之后支持转移字符:
# \n 回车换行
# \r 回车
# \v 换行
# \t Tab制表符距离
# \c 在字符串输入末尾不换行echo -e "请输入一个测试字符串:\c"; read testStr3
echo -e "\033[4;33;42m$testStr3\033[0m"#echo 加上 -n 选项,输出不换行
read -p "请输入一个测试字符串:" testStr4
echo -e -n "\033[5;35;41m${testStr4}\033[0m"
三、分支控制
1. 表达式
Shell脚本中的表达式分为算术表达式和逻辑表达式,算术表达式常用 let 进行赋值和计算,也可以用 ((表达式)) 双小括号进行算术表达式的赋值和计算。
除了Shell自身的算术表达式处理方式,还可以通过下载 bc 工具进行处理,也可用通过Shell脚本将字符串通过管道 | 传递给bc工具,让bc工具进行计算。
逻辑表达式常用 test 命令进行逻辑判断,test命令的退出码为0表示逻辑为true,否则为false,通常在test命令的后面跟上 echo $? 语句显示test命令的判断结果。
test命令在进行判断的时候,= 两边都需要空一格。
test命令可用 [ ] 中括号进行等价替换,注意 [ 和 ] 前后中括号之间都要有空格。
#!/bin/bashecho "算术计算:"
a=1
b=2
let c=$a+$b
echo $c((d=($a+$b)*$c))
echo $d
echo $(($c/$b))yum install -y bc
echo "$c/$b" | bc
echo "scale=2;$c/$b" | bc
# bc工具通过scale指定精度echo "逻辑判断:"
test $a = $b; echo $?
test $c = $(($a+$b)); echo $?# 复合条件判断
# -gt 大于,greater than
# -lt 小于,less than
# -ge 大于等于,greater or equal
# -le 小于等于,less or equal
# -eq 数值等于,equal
# -a 与,可用&&替换,and
# -o 或,可用||替换,orecho "复合条件判断:"
age=15
test $age -gt 10 -a $age -lt 20; echo $?
test $age -lt 10 -o $age -gt 20; echo $?[ $age -gt 10 ] && [ $age -lt 20 ]; echo $?
[ $age -le 10 ] || [ $age -ge 20 ]; echo $?# 文件和目录属性判断:
# -e 判断文件或目录是否存在
# -f 判断是否为文件以及是否存在
# -d 判断是否为目录以及是否存在
# -r -w -x 判断权限chmod u-x _02_expression.sh
[ -r _02_expression.sh ]; echo $?
[ -w _02_expression.sh ]; echo $?
[ -x _02_expression.sh ]; echo $?
chmod u+x _02_expression.sh
2. if 分支
逻辑判断语句通常会搭配 if 条件分支控制语句使用,if条件控制语句有单分支、双分支和多分支三种不同的格式。
#!/bin/bash# 单分支格式
if [ -f _01_hello.sh ]; thenecho "01FILE EXIST!"
fi# 双分支格式
if [ -f _02_hello.sh ]; thenecho "02FILE EXIST!"
elseecho "02FILE NOT EXIST!"
fi# 多分支格式
if [ -d _01_hello.sh ]; thenecho "01DIR EXIST!"
elif [ -f _01_hello.sh ]; thenecho "01FILE EXIST!"
elseecho "01FILE 01DIR NOT EXITS"
fi# 判断crond进程是否正常运行
name=crond
num=$(ps -ef|grep $name|grep -vc grep)
if [ $num -eq 1 ];thenecho "$num running!"
elseecho "$num is not running!"
fi
3. case 分支
case 变量值 in
模式 1)命令序列1;;
模式 2)命令序列2;;.......
*)默认命令序列;;
esac
case值得注意的特点:
- case行尾必须为单词"in",每一模式必须以右括号“)”结束
- 双分号";;"表示命令序列结束
- 模式字符串中,可以用方括号表示一个连续的范围,如"[0-9]";还可以用管道符号" | “表示或,如"A|B”
- 最后的 " *) " 表示默认模式,其中的 星号 相当于通配符
#!/bin/bashread -p "请输入一个字符:" inputcase "$input" in
[a-z]|[A-Z])echo "您输入的是一个字母";;
[0-9])echo "您输入的是一个数字";;
*)echo "您输入的是一个空格、功能键或其他按键";;
esac
四、循环控制
1. for 循环
for val in valuelist...
docommands
donefor((exp1;exp2;exp3))
docommands
done
# exp1 初始化
# exp2 变量取值范围
# exp3 变量增量
#!/bin/bashfor i in {1..5};
doecho -e "\033[${i}mhello world\033[0m"
donefor i in 1 3 5;
dofor j in 31 33 35 37;doecho -e "\033[${i};${j}mhello world\033[0m"done
done
2. while 循环
while 条件判断
docommand...
done# while后面的命令执行成功则循环,否则跳出循环
#!/bin/bashcount=3
while [ $count -ge 0 ]
doecho $countlet count=$count-1
donecount=3
while (($count >= 0))
doecho $count((count--))
done# 通过while实现shell脚本给文件内容添加行号
if [ -f $1 ]; theni=1cat $1 | while read textdoecho "$i:$text"((i++))done
elseecho "文件不存在"
fi
3. select 循环
select var in menu...
docommands
done# select 后面跟的是菜单
# in 关键字后面是菜单取值列表
# 这些值以空格隔开
# 用户选择数字对应菜单值
# 变量var获取值后执行循环一次
#!/bin/bashPS3="Please Select[1-4]"select m in one two three four exit;
doif [ $m = exit ]; thenbreakfiecho $m
done# PS3是一个环境变量,是select的提示符
五、函数
Shell的函数定义与C语言类似,需要先定义再调用原则,函数名后面接小括号,可以有参数或返回值,但是没有返回值类型。
#shell中的函数定义
#其中function为关键字,FUNCTION_NAME为函数名
function FUNCTION_NAME(){command1 #函数体中可以有多个语句,不允许有空语句command2...
}
#省略关键字function,效果一致
FUNCTION_NAME(){command1command2...
}# 函数名后的小括号中没有参数
# 函数function关键字可以不写
# 函数必须遵循先定义再调用原则
#!/bin/bashecho -n "请输入文件名:"
read FILE
function checkFileExist(){if [ -f $FILE ]; thenreturn 0elsereturn 1fi
}echo "call function checkFileExist"
checkFileExist
if [ $? -eq 0 ]; thenecho "$FILE exist"
elseecho "$FILE not exist"
fi
#!/bin/bashHello(){echo "hello world"
}Hello# 写一个函数判断文件是否存在
function CheckFileExist(){if [ -f $1 ]; thenreturn 0elsereturn 1fi
}read -p "请输入文件名:" filename
CheckFileExist $filenameif [ $? -eq 0 ]; thenecho "$filename is exits!"
elseecho "$filename is not exits!"
fi
由于Shell是一门面向过程的脚本型语言,而且用户主要是Linux系统管理人员,所以并没有非常活跃的社区,这也造成了Shell缺乏第三方函数库,所以在很多时候需要系统管理人员根据实际工作的需要自行开发函数库。下面建立一个叫 funclib 的函数库,该函数库目前只有一个函数,用于判断文件是否存在。
_checkFileExists(){if [ -f $1 ]; thenecho "File:$1 exists"elseecho "File:$1 not exist"fi
}
其他脚本在希望直接调用_checkFileExists函数时,可以通过直接加载 funclib 函数库的方式实现。加载方式有如下两种:
#使用“点”命令
$ . /PATH/TO/LIB#使用source命令
$ source /PATH/TO/LIB
假设现在有个脚本想要直接调用_checkFileExists函数,可以通过加载 funclib 函数库来实现。
可以通过 set 和 unset 命令查看当前内存中已经定义和载入的函数,使用 unset 清除函数,函数修改后必须重新载入。