Linux
十三 Shell编程
Shell编程在很多情况下有着使用。在进行Linux服务器集群管理时需要编写Shell程序以进行服务器管理;对于JavaEE和python开发,需要书写Shell脚本完成特定的任务,如定时备份数据库信息;大数据编程需要使用Shell程序管理集群。
- Shell是什么
Shell是一个命令行解释器,它为用户提供了一个面向Linux内核发送请求以便运行程序的系统界面级程序,用户可以使用Shell来启动、挂起、关闭甚至编写一些程序。
- Shell脚本运行方式
Shell脚本会以#!/bin/bash
标识作为开头,需要有可执行权限。在使用shell脚本时,需要赋予脚本可执行权限,并输入脚本的绝对路径或者相对路径以运行脚本。当然还可以使用指令sh + shell脚本
,这样可以不用对其附加可执行权限。
#!/bin/bash
echo "helloWorld!"
Shell变量
Linux系统Shell编程中的变量分为系统变量和自定义变量。
- 系统变量
$HOME
、$PWD
、$SHELL
、$USER
等,可以使用set
指令来查看当前系统中的所有变量
- 自定义变量
用户可以在Shell中自定义一些变量,也可以将自定义的Shell变量输出为环境变量,这样该变量就可以在其他Shell中使用了
- Shell变量的定义
可以使用变量名=变量值
的方式来定义一个变量,使用unset 变量名
的方式来撤销该变量,同时也可以使用readonly
来定义一个静态变量,需要注意的是,静态变量无法使用unset
来撤销。还可以将变量声明为全局环境变量,这样该变量就可以在其他Shell程序中使用了。
#!bin/bash
A=100
echo "A=$A"
unset A
echo "A=$A"
readonly B=2550
echo "B=$B"
#unset B 该指令使用时会出错 因此无法使用
echo"B=$B"
-
变量命名规则
变量名可以由字母、数字、下划线组成,不能以数字开头。
等号两侧不能有空格
变量名称一般习惯大写 -
将命令的返回值赋予变量
一般来说,将命令的返回值赋予变量比较常用,有两种书写格式- 将命令使用反引号包围
A=`ls -la`
- 将命令使用美元符号和括号包围,等价于反引号
A=$(ls -la)
- 将命令使用反引号包围
-
将变量输出为环境变量
在linux系统中,一般会在/etc/profile
文件中新增环境变量,如TOMCAT_HOME
、JAVA_HOME
等- 使用
export 变量名=变量值
可以将shell变量输出为环境变量 - 使用
source 配置文件
可以使修改以后的配置文件立即生效,一般来说在设置完配置文件后需要使用该指令 - 使用
echo $环境变量名
可以用来查询环境变量的值,如echo $JAVA_PATH
- 使用
-
位置参数变量
当执行一个shell脚本时,如果希望获取到命令行参数信息,可以使用到位置参数变量,能够在shell脚本中获取到参数信息。如sh myshell.sh 1500 2500
(即获取命令行中的参数1500和2500)
基本语法如下:$n
,n代表的是数字,该表达方式为获取位置为n的参数,$0
即为命令本身,10以上的参数使用${n}
来表示分隔$*
,代表命令行中的所有参数$@
,同样代表命令行中的所有参数,不过$@
会将每个参数区分对待,而$*
则会将参数看成是一个整体$#
,表示获取到命令行中参数的个数
#!/bin/bash
echo "输出第一个 第二个 第三个参数:$1 $2 $3"
echo "输出全部参数$@"
echo "输出全部参数$*"
echo "输出参数个数:$#"
- 预定义变量
是shell设计者预先定义好的变量,可以直接使用$$
,表示当前进程的进程号PID$!
,表示后台运行的最后一个进程的PID$?
,表示返回个最后一次执行命令的执行返回状态,如果为0
则表示执行成功
运算符
在shell中进行进行运算时需要使用到运算符,格式非常简单
- $((运算式))
,如$(($a + $b))
,但是不太常用,括号太多可读性比较差
- $[运算式]
,如$[$a + $b]
,该格式会比较常用
- expr `运算式`
,使用expr
指令可以进行四则运算
在使用expr
时需要注意,要使用空格隔开每个项,并且特殊字符需要使用反斜杠\
,比如*
RESULT=$[(2+3)*4]
RESULT2=`expr 2 + 3`
RESULT3=`expr $RESULT2 \* 5`
SUM=$[$A+$B]
条件判断
- 基本语法
[ condition ]
,注意:condition需要和中括号之间有空格分隔。当中括号内不是条件表达式时,当condition为非空则返回true,否则为false - 常用判断条件
- 整数判断:
-gt -lt - le -eq -ge -ne
- 字符串判断:
=
- 根据文件权限判断:
-e -w -x
- 根据文件类型判断
-f
:文件存在并且为常规文件-e
:文件存在-d
:文件存在且为常规目录
- 整数判断:
#注意if和中括号之间也需要有空格分隔
if [ "123" = "321"]
then echo "equal"
fi
流程控制
- if语句
if [ condition ]
then #DO SOMETHING
elif [ condition ]
then #DO SOMETHING
fi
- case语句
case $variate#变量名 in
"值1")
#DO SOMETHING
;;
"值2")
#DO SOMETHING
;;
"值3")
#DO SOMETHING
;;
*)
#表示默认值
;;
esac
- for循环
for循环是有两种形式的,一种是in形式,一种是括号形式
for 参数 in 值1 值2 值3 ...
do
#DO SOMETHING
done
#下面是实例演示
for i in $*
do
echo "it is $i"
done
for i in {1,2,3,4,5,6,7}
do
echo "$i"
done
for ((初始值;循环条件;变量变化))
do
#DO SOMETHING
done
#下面是实例演示
for ((i=0;i<=10;i++))
do
echo "$i"
done
- while循环
需要注意的是,在执行一些运算时,不要忘记使用运算符$(())
或者$[]
,这样能够避免一些错误的出现。
while [ 条件循环表达式 ]
do
#DO SOMETHING
done
#实例演示
#!bin/bash
i=1
sum=0
while ((i <= 100))
do
((sum += i))
((i++))
done
echo "The sum is: $sum"
#===========================
SUM=0
i=0
while [ $i -le $1 ]
do
SUM=$[$SUM+$i]
i=$[$i+1]
done
echo $SUM
- 使用
read
来读取控制台输入
在shell脚本中,可以使用read
指令来读取控制台输入的内容。基本语法为:read (选项) (参数)
选项有:-p
,用于指定读取值时的提示符-t
,用于指定读取值的等待时间(秒),超出时间则不在等待- 变量名,用于指定读取数值的变量
read -t 100 -p "请输入一个值:" NUMBER
echo "您输入的值为:$NUMBER"
函数
Shell编程和其他语言一样,有系统函数,也可以自定义函数。
- 系统函数
Shell的系统函数有很多,在此介绍两个- basename函数
basename函数可以用于返回完整路径的最后文件部分,或者删除字符串的最后一个反斜杠\
前面的所有前缀。常常用于获取文件名。基本语法为basename [pathname/string] [suffix]
。suffix表示为后缀,如果有该后缀,则basename函数会将suffix后缀也去掉。 - dirname函数
dirname函数常用于返回完整路径的最后一个/
前面的部分,常用于返回文件的路径信息。基本语法为dirname [文件绝对路径/string]
- basename函数
#!bin/bash
basename /home/abc/table.txt .txt#则表示会返回table
dirname /home/a/b/c/d.txt#表示会返回/home/a/b/c
- 自定义函数
自定义函数的格式如下:
function funcName(){
#DO SOMETHING
#return something
}
#!bin/bash
function getSum(){
SUM=$[$n1+$n2]
echo "和是$SUM"
}
read -p "请输入n1" n1
read -p "请输入n2" n2
getSum $n1 $n2
Shell脚本案例
在这里给出一个Shell脚本的案例以供参考
每天凌晨2:00时备份数据库信息,并且在备份开始和备份结束是提示信息。
备份后,文件要求以备份时间为文件名,并打包成tar.gz形式
备份同时检查是否有10天以前备份的库文件吗,如果有将其删除
#!bin/bash
echo "开始备份"
#需要注意的是,这里的两个环境变量需要在/etc/profile中定义并export输出成环境变量
echo "备份路径为$BACKUP/$DATETIME.tar.gz"
HOST=localhost
DB_USER=root
DB_PWD=root
DATABASE=jarvisDB
[ ! -d "$BACKUP/$DATETIME" ] && mkdir -p $BACKUP/$DATETIME
#开始备份数据库
msyqldump -u ${DB_USER} -p ${DB_PWD} --host ${HOST} $DATABASE | gzip $BACKUP/$DATETIME/$DATETIME.sql.gz
cd $BACKUP
tar -zcvf $DATETIME.tar.gz $DATETIME
rm -rf $DATETIME
find $BACKUP -mtime +10 -name "*.tar.gz" -exec rm-rf{}\;
#这里的find指令可以对查找到的文件进行操作,-mtime表示修改时间 ,-exec表示将文件传入后续{}中执行命令行操作