Fork me on GitHub

【linux进阶】Shell 脚本编程入门

一、Shell 编程入门

1. 认识 Shell

开发者在进行服务器集群管理时,都需要编写 Shell 程序来进行服务器管理。Shell 是一个命令行解释器,为用户提供了一个向 Linux 内核发送请求以便于运行程序的界面系统升级程序。用户可以用 Shell 来启动、挂起、停止或者编写一些程序。

2. Shell 脚本的创建与执行

Shell 脚本在执行时有两个格式上的要求:以 #!/bin/bash 开头、必须有可执行权限。如下我们编写第一个 Shell 脚本:
(1)创建新目录 shell 用于存放 shell 脚本;

[root@majinjian ~]#mkdir /root/shell

[root@majinjian ~]# cd /root/shell

(2)vim 编辑器新建 shell 脚本 shell.sh,输入命令;

#!/bin/bash
echo "hello world!"

3)这个时候查看 shell.sh 的权限,是没有可执行权限 x 的;

 4)为它添加可执行权限;

[root@majinjian shell]# chmod u+x shell.sh 

shell 脚本常用的执行方式有两种:
● 输入脚本的绝对路径或者相对路径(需要先赋予脚本执行权限 x);
● sh + 脚本(无需赋予执行权限,直接执行即可)。

二、Shell 变量

1. 系统变量和自定义变量

Linux Shell 中的变量分为系统变量和用户自定义变量。系统变量顾名思义就是系统已经设置好的变量,诸如 $HOME、$PWD、$USER、$SHELL 等都是系统变量。使用指令 set 可以查看系统中所有的系统变量。我们常用较多的是自定义变量,基本语法如下:

● 定义变量:变量名称=值;
● 撤销变量:unset 变量名;
● 定义静态变量:readonly 变量名称=值(静态变量不能撤销);
● 输出变量:$变量。

我们试着操作一下变量:

#定义变量A
A=100
 
#输出变量
echo A=$A
echo "A=$A"
 
#撤销变量A
unset A
echo $A
 
#声明静态的变量B = 3
readonly B=3
echo $B

执行结果为;

2. 变量的基本规则

在定义变量时变量名称可以由字母、数字和下划线组成,但不能以数字开头;等号的两侧不能有空格;变量名称一般为大写。
将命令的返回值赋给变量时使用如下写法;

A=`data`,表示运行 ` ` 中的命令,并把结果返回给 A;
A=$(data),$() 相当于 ``。

3. 设置环境变量

export 变量名=变量值 //将 Shell 变量输出为环境变量/全局变量
source 配置文件 //让修改后的配置信息立即生效
echo $变量名 //查询环境变量的值

案例:在 /etc/profile 文件中定义 TOMCAT_HOME 环境变量,vim 打开 /etc/profile 输入;

export TOMCAT_HOME=/opt/tomcat

设置完之后刷新配置状态;

[root@majinjian opt]# source /etc/profile

结果如下;

4. 位置参数变量

当执行一个 Shell 脚本时,如果希望获取到命令行的参数信息,就需要使用到位置参数变量。基本语法有:

$n  //n 为数字,$0 代表命令本身,$1-9 代表第 1 到第 9 个参数,10 以上的参数需要用大括号包含如 ${10}
$*  //代表命令行中的所有参数,$* 将所有参数看成一个整体
$@  //这个变量也可以代表命令行中的所有参数,不过 $@ 把每个参数区分对待
$#  //代表命令行中所有参数的个数

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

#!/bin/bash
echo "0=$0 1=$1 2=$2"
echo "所有参数=$*"
echo "$@"
echo "参数个数=$#"

运行时输入 100 和 200 两个参数,结果如下。

5. 预定义变量

预定义变量就是 Shell 的设计者事先定义好的变量,可以直接在 Shell 脚本中使用。基本语法有:

$$  //当前进程的进程号码(PID)
$!  //后台运行的最后一个进程的进程号
$?  //最后一次执行命令的返回状态,如果这个变量的值为0证明上一个命令正确执行,如果不是 0 上一个命令没有正确执行

三、运算符

在 Shell 编程中有各种运算操作,语法格式为 $((运算式)) 或 $[运算式] 或者 expr m + n;如果希望将 expr 的值赋给某个变量,使用 `` 即可。

\* //乘,在 `` 里面的乘应该用此格式即 * 前添加转义字符 \
/ //除
% //取余

案例1:计算 (2+3)×4;

#!/bin/bash
#计算(2+3)×4的值
 
#方式1
result1=$(((2+3)*4))
echo "res1=$result1"
 
#方式2
result2=$[(2+3)*4]
echo "res2=$result2"
 
#方式3
result3=`expr 2 + 3`
result4=`expr $result3 \* 4`
echo "expr res4=$result4"

结果如下。

 案例2:计算命令行两个参数的和;

#计算命令行两个参数的和
sum=$[$1+$2]
echo "sum=$sum"

运行时输入 20 和 50,结果如下:

四、条件判断

条件判断使用语法 [ condition ](注意 condition 前后有空格),非空会返回 true。可以使用 $? 验证结果,0 为 true,>1 为false。如:

[ hspEdu ] 会返回 true
[ ] 会返回 false
[ condition ] && echo yes || echo no ,前一个判断满足时会继续执行后面的语句

 常用的判断语句有:

判断两个字符串

=  //相等
判断两个整数

-lt  //小于
-le  //小于等于
-eq  //等于
-gt  //大于
-ge  //大于等于
-ne  //不等于
按照文件权限进行判断

-r  //有读的权限
-w  //有写的quanx
-x  //有执行的权限
按照文件类型进行判断

-f  //文件存在并且是一个常规的文件
-e  //文件存在
-d  //文件存在并是一个目录

案例:判断 "ok" 是否等于 ok; 

#!/bin/bash
if [ "ok" = "ok" ]
then
echo "equal" #如果等于则输出 equal
fi  #否则结束

22 是否大于等于 21;  

if [ 22 -ge 21 ]
then
echo "大于"
fi

/root/shell 目录下是否有 aaa.txt 文件;  

if [ -f /root/shell/aaa.txt ]
then
echo "存在"
fi

执行结果如下:

五、流程控制

1. if 语句

if 语句的基本语法如下,需要注意 [ 条件判断式 ] 中括号与判断式之间必须有空格。

#单分支
if [ 条件判断式 ]
then
代码
fi

 

#多分支
if [ 条件判断式 ]
then
代码
elif [ 条件判断式 ]
then
代码
fi

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

#!/bin/bash
if [ $1 -ge 60 ]
then
        echo "及格"
elif [ $1 -le 60 ]
then
        echo "不及格"
fi

运行时带参数结果如下;

2. case 语句

基本语法如下,其中 * 代表都不是以上的值。

case $变量名 in
"值1")
如果变量的值等于1,则执行程序1
;;
"值2")
如果变量的值等于2,则执行程序2
;;
......
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac

案例:编写 Shell 程序当命令行参数为 1 时输出“周一”,是 2 时输出“周二”,其他情况均输出“other”  

#!/bin/bash
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
*)
echo "other"
;;
esac

运行结果如下:

3. for 循环

for 循环有两个基本语法,语法一:

for 变量 in 值1 值2 值3...
do
程序
done

案例1:打印命令行输入的参数;

#!/bin/bash
#使用$*
for i in "$*"
do
echo "num is $i"
done
 
#使用$@
for i in "$@"
do
echo "num is $i"
done

运行结果如下,这也印证了 $*(将所有参数看成一个整体) 和 $@(将参数区别对待) 的区别;  

 除此之外 for 循环还有第二个语法;

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

案例2:输出从 1 加到 100 的值。  

#!/bin/bash
sum=0
for(( i=1;i<=100;i++ ))
do
sum=$[$sum+$i]
done
echo "SUM=$sum"

运行结果如下:

4. while 循环

基本语法:

while [ 条件判断式 ]
do
程序
done

案例:命令行输入一个参数 n,计算 1+2+..+n 的值;

#/bin/bash
sum=0
i=0
while [ $i -le $1 ]  #只要第i个数小于我们输入的参数,就执行循环
do
sum=$[$sum+$i]
i=$[$i+1]  #i自增
done
echo "SUM=$SUM"

运行结果如下:

六、read 读取控制台输入

 在我们进行 Shell 编程的时候,有时候也需要跟控制台进行交互,比如用户动态的输入一些数据,这个时候就需要用到 read。基本语法为 

read(选项)(参数)

-p 制定读取值时的提示符
-t 指定读取值时的等待时间,如果没有在规定时间内输入,则不再等待

 案例 1:读取控制台输入一个 num 值;

#!/bin/bash
read -p "输入num1=:" num1
echo "你输入的num1为:$num1"

 案例 2:读取控制台输入一个 num 值,指定在 10 秒内输入;

read -t 10 -p "输入num2=" num2
echo "你输入的num2为:$num2"

运行结果如下:

七、函数

定义函数方式如下:

 

myfunc() 
{
echo "hello world $1"
}

 

或者:

function myfunc() 
{
    echo "hello world $1"
}

函数调用:

para1="shouwang"
myfunc $para1

八、返回值

通常函数的return返回值只支持0-255,因此想要获得返回值,可以通过下面的方式

function myfunc() {
    local myresult='some value'
    echo $myresult
}
val=$(myfunc)  #val的值为some value

通过return的方式适用于判断函数的执行是否成功

function myfunc() {
    
    #do something
    return 0
}
if myfunc;then
    echo "success"
else
    echo "failed"
fi

九、注释

shell通过#来注释一行内容,前面我们已经看到过了:

#!/bin/bash
# 这是一行注释
:'
这是
多行
注释
'
ls

:<<EOF
这也可以
达到
多行注释
的目的
EOF

 

十、日志保存

脚本执行后免不了要记录日志,最常用的方法就是重定向。以下面的脚本为例:

#!/bin/bash
#test.sh
lll  #这个命令是没有的,因此会报错
date

方式一,将标准输出保存到文件中,打印标准错误:

./test.sh > log.dat

这种情况下,如果命令执行出错,错误将会打印到控制台。所以如果你在程序中调用,这样将不会讲错误信息保存在日志中。

方式二,标准输出和标准错误都保存到日志文件中:

./test.sh > log.dat 2>&1

2>&1的含义可以参考《如何理解linuxshell中的2>&1

方式三,保存日志文件的同时,也输出到控制台:

./test.sh |tee log.dat

十一、脚本执行

最常见的执行方式前面已经看到了:

./test.sh

其它执行方式:

sh test.sh  #在子进程中执行
sh -x test.sh #会在终端打印执行到命令,适合调试
source test.sh #test.sh在父进程中执行
. test.sh   #不需要赋予执行权限,临时执行

十二、脚本退出码

很多时候我们需要获取脚本的执行结果,即退出状态,通常0表示执行成功,而非0表示失败。为了获得退出码,我们需要使用exit。例如

#!/bin/bash
function myfun()
{
    if [ $# -lt 2 ]
    then
       echo "para num error"
       exit 1
    fi
    echo "ok"
    exit 2
}
if [ $# -lt 1 ]
then
   echo "para num error"
    exit 1
fi

returnVal=`myfun aa`
echo "end shell"
exit 0

  

  

  

  

  

  

  

  


  

  

 


  

 

  

 

 

  

  

  

  

  

  

  

 

 

 

 

 

https://www.cnblogs.com/weijiqian/p/16385458.html

 

https://www.yanbinghu.com/2019/05/07/53959.html

 

  

  

  

  

  

 

  

  

  

  

  

  

 

posted @ 2023-05-22 18:42  橘子偏爱橙子  阅读(1244)  评论(0编辑  收藏  举报