1. Shell脚本入门

1.1 脚本格式要求

  1. 脚本以#!/bin/bash开头

  2. 脚本需要有执行权限

1.2 shell脚本的执行方式

  1. 输入脚本的绝对路径或相对路径

    • 需要对脚本+x权限,再执行脚本
  2. sh + 脚本

    • 不需要对脚本+x权限,直接执行即可

案例:创建一个shell脚本,输出hello,world:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mkdir /root/shcode              #创建一个写shell脚本的文件夹
vim hello.sh #在shcode目录下以vim文本编辑器编辑脚本

#输入内容如下:
#!/bin/bash
echo “hello,world” #保存退出

#第一种方式执行(终端输入)
chmod u+x hello.sh #让该用户对文件有执行的权限
./hello.sh #1相对路径执行
/root/shcode/hello.sh #2绝对路径执行
#第二种方式执行(不需要权限,终端直接输入)
sh hello.sh #1相对路径执行
sh /root/shcode/hello.sh #2绝对路径执行

2. 变量

2.1 shell变量

Linux shell中的变量分为,系统和用户自定义变量

  1. 系统变量:$HOME、$PWD、$SHELL、$USER等等,比如echo $HOME

    • 显示当前shell中所有变量:set
  2. shell变量的定义(自定义变量)

    • 定义变量:变量名=值

    • 撤销变量:unset 变量

    • 声明静态变量,声明后不能unset:readonly 变量

  3. 定义变量的规则

    • 变量名可以由字母、数字和下划线组成,但是不能以数字开头,

    • 等号两侧不能有空格,如:A=100

    • 变量名称一般习惯为大写,这是一个规范

  4. 将命令的返回值赋给变量

    • A=’date’反引号(键盘左上角第二颗键),运行里面的命令,并把结果返回给变量A

    • A=$(date)等价于反引号

案例:在var.sh里自定义变量、撤销变量、声明静态变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
#案例1:定义变量
A=100
#输出变量需要加上$
echo A=$A #第1种方法输出变量A
echo "A=$A" #第2种方法输出变量A
#案例2:撤销变量A
unset A
#撤销后输出不会报错,但会无结果
echo "A=$A" #输出无结果
#案例3:声明静态的变量B=2,不能unset
readonly B=2
echo B=$B #输出变量B
#撤销静态变量会报错
unset B #报错
#将指令返回的结果赋给变量
C=`date` #第1种方式将命令的返回值赋给变量
D=$(date) #第2种方式将命令的返回值赋给变量
echo C=$C
echo "D=$D"

输出结果如下:

2.2 设置环境变量

  1. 将shell变量输出为环境变量/全局变量(/etc/profile文件夹)
  • export 变量名=变量值
  1. 配置文件,让修改后的配置信息立即生效(终端输入)
  • source
  1. 查询环境变量的值
  • echo $变量名

案例:在/etc/profile文件中定义TOMCAT_HOME环境变量,并查询其环境变量值

1
2
3
4
5
6
7
8
#以vim文本编辑器形式打开文件profile
vim /etc/profile
#在最后一行输入这条命令,保存并退出
export TOMCAT_HOME=/opt/tomcat
#令修改的信息立即生效
source /etc/profile
#然后就可以在shell程序中使用了
echo $TOMCAT_HOME

补:shell脚本的多行注释::<<! 内容 ! ——->后面的!需要单独起行

2.3 位置参数变量

当我们执行一个shell脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变量。比如:./myshell.sh 100 200,这个就是一个执行shell的命令行,可以在myshell脚本中获取到参数信息。

  • $n:n为数字,$n代表本身,$1-$9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10};

  • $*:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整数

  • $@:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待

  • $#:这个变量代表命令行中所有参数的个数

案例:编写一个shell脚本position.sh,在脚本中获取到命令行的各个参数信息

1
2
3
4
5
6
7
8
#以vim文本编辑器打开
vim /root/shcode/myshell.sh
#内容代码
#!/bin/bash
echo "0=$0 1=$1 2=$2" #打印第0、1、2位置的参数
echo "所有的参数=$*" #输出所有参数,不包括$0
echo "$@" #输出所有参数,不包括$0
echo "参数的个数=$#" #输出参数的个数

输出结果如下:

2.4 预定义变量

就是shell设计者事先已经定义好的变量,可以直接在shell脚本中使用

  • $$:当前进程的进程好PID;

  • $!:后台运行的最后一个进程的进程号PID;

  • $?:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,有命令自己来决定),则证明上一个命令执行不正确。

案例:在一个shell脚本中简单使用一下预定义变量preVar.sh

1
2
3
4
5
6
#!/bin/bash
echo "当前执行的进程id=$$"
#以后台方式运行一个脚本,并获取它的进程号
/root/shcode/myshell.sh &
echo "最后一个后台方式运行的进程id=$!"
echo "执行的结果是=$?"

输出结果如下:

2.5 运算符

  1. $((运算符))或$[运算符]或者expr m 运算符 n

  2. 注意expr运算符间要有空格,如果希望将expr的结果赋给某个变量,使用``(左上角键)

  3. expr m 运算符 n 方式下的运算符

    • expr *,/,% ———–>乘,除,取余

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
#案例1:计算(2+3)*4的值
#使用第1种方式:
res1=$(((2+3)*4))
echo "res1=$res1"
#使用第2种方式:
res2=$[(2+3)*4]
echo res2=$res2
#使用第3种方式(数字之间要要空格):
TEMP=`expr 2 + 3`
RES3=`expr $TEMP \* 4`
echo res3=$RES3

#案例2:请求出命令行的前两个参数的和(20+50)
SUM=$[$1+$2]
echo sum=$SUM

输出的结果如下:

3. shell进阶

3.1 条件判断

基本语法:

  • [ condition ] 括号非空返回true,可以使用$?验证
  • [ condition ] && echo ok || echo notok 条件满足,执行后面的语句

应用实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!bin/bash
#案例1:"ok"是否等于"ok"
if [ "ok" = "ok" ]
then
echo "equal"
fi
#案例2:23是否大于等于22
if [ 23 -ge 22 ]
then
echo "大于等于"
fi
#案例3:/root/shcode/aaa.txt 文件是否存在
if [ -f /root/shcode/aaa.txt ]
then
echo "存在"
fi
#案例4:测试空
if [ lxx ]
then
echo "hello world"
fi

输出的结果如下:

3.2 流程控制

1.多分支

if [ 条件判断式 ]

then

​ 代码

elif [ 条件判断式 ]

then

​ 代码

fi

注:[ 条件判断式 ],中括号和条件判断式之间必须有空格,fi表示结束

案例:请编写一个shell程序,如果输入的参数。大于等于60,则输出”及格了”,如果小于60,则输出”不及格”

1
2
3
4
5
6
7
8
#!bin/bash
if [ $1 -ge 60 ]
then
echo "及格了"
elif [ $1 -lt 60 ]
then
echo "不及格"
fi

输出结果如下:

2.case语句

case $变量名 in

“值1”)

如果变量的值等于1,则执行程序1

;;

“值2”)

如果变量的值等于2,则执行程序2

;;

….省略其他分支…

*)

如果变量的值都不是以上的值,则执行此程序

;;

esac

案例:当命令行参数是1时,输出”周一”,是2时,就输出”周二”,其他情况输出”other”

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
*)
echo "other..."
;;
esac

输出结果如下:

3.for循环(第1种)

for 变量 in 值1 值2 值3

do

程序/代码

done

案例:打印命令行输入的参数[这里可以看出$*和$@的区别]:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
#注意 $*是把输出的参数,当作一个整体,所以只会输出一句
for i in "$*"
do
echo "num is $i"
done
#使用$@来获取输入的参数,注意,这时是分别对待,所以有几个参数,就输出几句
echo "------------------------------"
for j in "$@"
do
echo "num is $j"
done

输出结果如下:

4.for循环(第2种)

for((初始值;循环控制条件;变量变化))

do

程序/代码

done

案例:从1加到100的值输出显示(若想将1001变为一个变量,可以将100改为$1)

1
2
3
4
5
6
7
8
#!/bin/bash
SUM=0 #定义一个变量SUM
for((i=1;i<=100;i++))
do
#写业务代码
SUM=$[$SUM+$i]
done
echo "总和SUM=$SUM"

输出结果如下:

5.while循环

while [ 条件判断式 ]

do

程序/代码

done

注意:while和[有空格,条件判断式和[也有空格

案例:从命令行输入一个数n,统计从1+…+n的值是多少

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
SUM=0; #定义一个变量SUM
i=0;
while [ $i -le $1 ]
do
#写业务代码
SUM=$[$SUM+$i]
i=$[$i+1]
done
echo "执行结果=$SUM"

输出结果如下:

4. read读取控制台输入

基本语法:read (选项) (参数)

选项:

  • -p:指定读取值时的提示符;

  • -t:指定读取值时等待的时间(秒),如果没有在指定的时间内输入,就不再等待了;

参数:

  • 指定读取值的变量名

案例:读取控制台输入一个NUM1值;读取控制台输入一个NUM2值,在10秒内输入

1
2
3
4
5
6
7
#!/bin/bash
#读取控制台输入一个NUM1
read -p "请输入一个NUM1=" NUM1
echo "您输入的NUM1=$NUM1"
#读取控制台输入一个NUM2,并要求在10秒内输入
read -t 10 -p "请输入一个数NUM2=" NUM2
echo "您输入的NUM2=$NUM2"

输出的结果如下(第一次是在10秒内输入了93,第二次是没有在10秒内输入数据):

5. 函数

shell编程和其他编程语言一样,有系统函数,也可以有自定义函数,下面介绍2个

5.1 系统函数

  • basename:返回完整路径最后/的部分,常用于获取文件名

  • dirname:返回完整路径最后/的前面的部分,常用于返回路径部分

案例:请返回/home/aaa/test.txt的test.txt部分

案例:请返回/home/aaa/test.txt的/home/aaa部分

5.2 自定义函数

案例:计算输入两个参数的和(动态获取)getSum

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
function getSum(){
SUM=$[$n1+$n2]
echo "和是=$SUM"
}
#输入两个值
read -p "请输入一个数n1=" n1
read -p "请输入一个数n2=" n2
#调用自定义函数
getSum $n1 $n2

输出的结果如下: