[X]关闭

关于shell脚本的学习

文档创建者:东吴
浏览次数:1713
最后更新:2024-04-01
本帖最后由 东吴 于 2024-4-1 16:16 编辑

一、shell入门简介
1.1shell概述
  Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
  它虽然不是Linux系统核心的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Linux系统的关键。
图片16.jpg
  可以说,shell使用的熟练程度反映了用户对Linux使用的熟练程度。

1.2几种常见的Shell
  前面提到过,Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本。
  Linux上常见的Shell脚本解释器有bash、sh、ash、csh、ksh,习惯上把它们称作一种Shell。我们常说有多少种Shell,其实说的是Shell脚本解释器。
  bash:是Linux系统默认使用的shell。bash由Brian Fox和Chet Ramey共同完成,是BourneAgain Shell的缩写,内部命令一共有40个。
  Linux使用它作为默认的shell是因为它有诸如以下的特色:
  •可以使用类似DOS下面的doskey的功能,用方向键查阅和快速输入并修改命令。
  •自动通过查找匹配的方式给出以某字符串开头的命令。
  •包含了自身的帮助功能,你只要在提示符下面键入help就可以得到相关的帮助。
  sh:由Steve Bourne开发,是Bourne Shell的缩写,各种UNIX系统都配有sh。
  ash:是由Kenneth Almquist编写的,Linux中占用系统资源最少的一个小shell,它只包含24个内部命令,因而使用起来很不方便。
  csh:是Linux比较大的内核,它由以William Joy为代表的共计47位作者编成,共有52个内部命令。该shell其实是指向/bin/tcsh这样的一个shell,也就是说,csh其实就是tcsh。
  ksh:是Korn shell的缩写,由Eric Gisin编写,共有42条内部命令。该shell最大的优点是几乎和商业发行版的ksh完全兼容,这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。

1.3第一个shell脚本
  1、需求:创建一个Shell脚本,输出helloworld
  2、案例实操:
  touch Helloworld.sh
  vim Helloworld.sh
  在Helloworld.sh中输入如下内容
   图片20.jpg
  chmod +x Helloworld.sh  #使脚本具有执行权限
  ./Helloworld.sh  #执行脚本
   图片21.jpg
  3、脚本的常用执行方式
  第一种:采用bash或sh+脚本的相对路径或绝对路径(不用赋予脚本+x权限)
  sh+脚本的相对路径
  sh Helloworld.sh
  Hello world!
      图片17.jpg
  sh+脚本的绝对路径
  sh /home/uisrc/Helloworld.sh
  Hello world!
      图片18.jpg
  bash+脚本的相对路径
  bash Helloworld.sh
  Hello world!
图片9.jpg
  bash+脚本的绝对路径
  bash /home/uisrc/Helloworld.sh
  Hello world!
图片10.jpg
  第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)
  首先要赋予Helloworld.sh 脚本的+x权限
  chmod 777 Helloworld.sh
  执行脚本
  相对路径
  ./Helloworld.sh
  Hello world!
  绝对路径
  /home/uisrc/helloworld.sh
  Hello world!
   图片11.jpg
  注意:第一种执行方法,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。

二、shell环境变量
2.1shell系统变量
1. 常用系统变量
$HOME、$PWD、$SHELL、$USER等
2.案例实操
1)查看系统变量的值
echo $HOME
/root
2)显示当前Shell中所有变量:set
set
BASH=/bin/bash
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()

2.2 自定义变量
1.基本语法
1)定义变量:变量=值
2)撤销变量:unset 变量
3)声明静态变量:readonly变量(注意:不能unset)
2.变量定义规则
(1)注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
(2)只包含字母、数字和下划线:变量名可以包含字母(大小写敏感)、数字和下划线,不能包含其他特殊字符。
(3)不能以数字开头:变量名不能以数字开头,但可以包含数字。
(4)避免使用 Shell 关键字:不要使用Shell的关键字(例如 if、then、else、fi、for、while 等)作为变量名,以免引起混淆。
5)使用大写字母表示常量:习惯上,常量的变量名通常使用大写字母,例如PI=3.14。
(6)避免使用特殊符号:尽量避免在变量名中使用特殊符号,因为它们可能与 Shell 的语法产生冲突。
(7)避免使用空格:变量名中不应该包含空格,因为空格通常用于分隔命令和参数。
3.案例实操
1)定义变量A
A=5
echo $A
输出结果为:
5
2)给变量A重新赋值
A=8
echo $A
输出结果为:
8
3)撤销变量A
unset A
echo $A
图片12.jpg
4)声明静态的变量B=2,不能unset
readonly B=2
echo $B
输出结果为:
2

B=9
输出结果为:
bash: B: readonly variable
图片13.jpg
5)在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
C=1+2
echo $C
输出结果为:
1+2
(6)变量的值如果有空格,需要使用双引号或单引号括起来
D=I love you
输出结果为:
-bash: world: command not found
D="I love you"
echo $A
输出结果为:
I love you
(7)可把变量提升为全局环境变量,可供其他Shell程序使用export变量名
vim helloworld.sh
在helloworld.sh文件中增加echo $B
图片14.jpg
输出结果为
./helloworld.sh
Hello world!
发现并没有打印输出变量B的值。
export B
./helloworld.sh
输出结果为:
helloworld
2
   图片15.jpg

2.3 特殊变量:$n
1.基本语法
$n(功能描述:n为数字,$0代表该脚本名称,$1-$9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10})
2.案例实操
输出该脚本文件名称、输入参数1和输入参数2 的值
touch parameter.sh
vim parameter.sh

#!/bin/bash
echo "$0  $1   $2"

chmod 777 parameter.sh
./parameter.sh xxx zz
输出结果为:
./parameter.sh xxx zz
2.4 特殊变量:$#
1.基本语法
$#        (功能描述:获取所有输入参数个数,常用于循环)。
2.案例实操
获取输入参数的个数
vim parameter.sh

#!/bin/bash
echo "$0  $1   $2"
echo $#
chmod 777 parameter.sh
./parameter.sh xxx zz
输出结果为:
parameter.sh xxx zz
2
2.5 特殊变量:$*、$@
1.基本语法
$*(功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体)
$@(功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待)
2.案例实操
打印输入的所有参数
vim parameter.sh

#!/bin/bash
echo "$0  $1   $2"
echo $#
echo $*
echo $@

./parameter.sh xxx yyy zzz
输出结果为:
parameter.sh xxx yyy
3
xxx yyy zzz
xxx yyy zzz
2.6 特殊变量:$?
1.基本语法
功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。
2.案例实操
判断helloworld.sh脚本是否正确执行
vim parameter.sh

      #!/bin/bash
      echo "$0  $1   $2"
      echo $#
      echo $*
      echo $@

      ./parameter.sh xxx yyy zzz
     输出结果为:
      parameter.sh xxx yyy
      3
      xxx yyy zzz
      xxx yyy zzz
三 、shell基本运算符
3.1算术运算符
运算符
说明
+
对两个变量做加法
-
对两个变量做减法
*
对两个变量做乘法
/
对两个变量做除法
**
对两个变量做幂运算
%
取模运算,第一个变量除以第二个变量求余数
+=
加等于,在自身基础上加第二个变量
-=
减等于,在第一个变量的基础上减去第二个变量
*=
乘等于,在第一个变量的基础上乘以第二个变量
/=
除等于,在第一个变量的基础上除以第二个变量
%=
取模赋值,第一个变量对第二个变量取模运算,再赋值给第一个变量

shell中有三种方法可以更改运算顺序:
1、用expr改变运算顺序。可以用echo `expr 1 + 2`来输出1+2的结果,用expr表示后面的表达式为一个数学运算。需要注意的是,`并不是一个单引号,而是“Tab”键上面的那个符号。
2、用let指示数学运算。可以先将运算的结果赋值给变量b,运算命令是b=let1 + 2。然后用echo $b来输出b的值。如果没有let,则会输出1+2。
3、用$[]表示数学运算。将一个数学运算写到$[]符号的中括号中,中括号中的内容将先进行数学运算(中括号中可以包含空格)。例如命令echo $[1+2],将输出结果3。
3.2关系运算符
运算符
说明
-eq
检测两个数是否相等,相等返回 true
-ne
检测两个数是否不相等,不相等返回 true
-gt
检测左边的数是否大于右边的,如果是,则返回 true
-lt
检测左边的数是否小于右边的,如果是,则返回 true
-ge
检测左边的数是否大于等于右边的,如果是,则返回 true
-le
检测左边的数是否小于等于右边的,如果是,则返回 true
输入test 1 -lt 2 && echo "yes"则打印yes

3.3布尔运算符
运算符
说明
举例
-a
(and)与运算,两状况同时成立
test -r file -a -x file,则file同时具有r和x权限时,才为true
-o
(or)或运算,两状况任何一个成立
test -r file -o -x file,则file具有r或x权限时,就为true。

非运算,相反状态
test!-r file,当file不具有r权限时,就为true

3.4逻辑运算符
运算符
说明
&&
逻辑的AND
||
逻辑的OR

3.5字符串运算符
运算符
说明
=
两个字符串相等

!=
两个字符串不相等

-z
空串
-n
非空串
$
检测字符串是否不为空,不为空返回true

输入test "a" = "a" && echo "yes"则打印yes

3.6文件测试运算符
运算符
说明
-b
检测文件是否是块设备文件
-c
检测文件是否是字符设备文件
-d
检测文件是否是目录
-f
测文件是否是普通文件(既不是目录,也不是设备文件)
-g
检测文件是否设置了 SGID 位
-k
检测文件是否设置了粘着位(Sticky Bit)
-p
检测文件是否是有名管道
-u
检测文件是否设置了 SUID 位
-r
检测文件是否可读
-w
检测文件是否可写
-x
检测文件是否可执行
-s
检测文件是否为空(文件大小是否大于0)
-e
检测文件(包括目录)是否存在

四、shell流程编程控制语句
4.1 if 判断
1、基本语法
1)单分支
    if [ 条件判断式 ];then
     程序
      fi
     或者
      if [ 条件判断式 ]
      then
     程序
      fi
2)多分支
if [ 条件判断式 ]
then
程序
elif [ 条件判断式 ]
then
程序
else
程序
fi
注意事项:
①[ 条件判断式 ],中括号和条件判断式之间必须有空格
②if 后要有空格
2、案例实操
输入一个数字,如果是 1,则输出xxx zhen shuai,如果是 2,则输出 xxx zhen mei,如果是其它,什么也不输出。
touch if.sh
vim if.sh

#!/bin/bash
if [ $1 -eq 1 ]
then
echo "xxx zhen shuai"
elif [ $1 -eq 2 ]
then
echo "xxx zhen mei"
fi

chmod 777 if.sh
./if.sh 1
输出结果为:
xxx zhen shuai
./if.sh 2
输出结果为:
Xxx zhen mei

4.2 case 语句
1、基本语法
case $变量名 in
"值 1")
如果变量的值等于值 1,则执行程序 1
;;
"值 2")
如果变量的值等于值 2,则执行程序 2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
注意事项:
1)case 行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
(2)双分号“;;”表示命令序列结束,相当于 java 中的 break。
3)最后的“*)”表示默认模式,相当于 java 中的 default。
2、案例实操
输入一个数字,如果是 1,则输出 xxx,如果是 2,则输出 yyy,如果是其它,输出zzz。
touch case.sh
vim case.sh

#!/bin/bash
case $1 in
"1")
echo "xxx"
;;
"2")
echo "yyy"
;;
*)
echo "zzz"
;;
esac

chmod 777 case.sh
./case.sh 1
输出结果为:
xxx
./case.sh 2
输出结果为:
yyy
./case.sh 3
输出结果为:
zzz
4.3 for 循环
1、基本语法 1
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
案例实操 :从 1 加到 100
touch for1.sh
vim for1.sh

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

chmod 777 for1.sh
./for1.sh
输出结果为
sum=5050
2、基本语法 2
for 变量 in 值 1 值 2 值 3…
do
程序
done
案例实操
1)打印所有输入参数
touch for2.sh
vim for2.sh

#!/bin/bash
#打印数字
for i in aa bb cc
do
echo "xxx love $i"
done
chmod 777 for2.sh
./for2.sh
输出结果为:
xxx love aa
xxx love bb
xxx love cc
2)比较$*和$@区别
$*和$@都表示传递给函数或脚本的所有参数,不被双引号“”包含时,都以$1 $2 …$n的形式输出所有参数。
touch for3.sh
vim for3.sh


#!/bin/bash
echo '=============$*============='
for i in $*
do
echo "xxx love $i"
done
echo '=============$@============='
for j in $@
do
echo "xxx love $j"
done


chmod 777 for3.sh
./for3.sh cls mly wls
输出结果为:
=============$*=============
xxx love cls
xxx love mly
xxx love wls
=============$@=============
xxx love cls
xxx love mly
xxx love wls
当它们被双引号“”包含时,$*会将所有的参数作为一个整体,以“$1 $2 …$n”的形式输出所有参数;$@会将各个参数分开,以“$1” “$2”…“$n”的形式输出所有参数。
vim for4.sh


#!/bin/bash
echo '=============$*============='
for i in "$*"
#$*中的所有参数看成是一个整体,所以这个 for 循环只会循环一次
do
echo "xxx love $i"
done
echo '=============$@============='
for j in "$@"
#$@中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次
do
echo "ban zhang love $j"
done


chmod 777 for4.sh
./for4.sh cls mly wls
输出结果为:
=============$*=============
xxx love cls mly wls
=============$@=============
xxx love cls
xxx love mly
xxx love wls

4.4 while 循环
基本语法
while [ 条件判断式 ]
do
程序
done
案例实操:从 1 加到 100
touch while.sh
vim while.sh

#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum

chmod 777 while.sh
./while.sh
输出结果为:
5050

五、shell函数
使用函数来执行重复性的任务,是一个很好的方式来创建代码的重用。
代码重用是现代面向对象编程的原则的重要组成部分。

5.1 创建函数:
声明一个函数语法:
function_name () {
例子:
#!/bin/bash
# Define your function here
Hello () {
echo "Hello World"
}
# Invoke your function
Hello

当你想执行上面的脚本,它会产生以下结果:
Hello World

5.2 参数传递给函数
你可以定义一个函数,它接受参数,而调用这些函数。将这些参数代表$1,$2,依此类推。
例子:
#!/bin/bash
# Define your function here
Hello () {
echo "Hello World $1 $2"
}
# Invoke your function
Hello Zhang lisi

这将产生以下结果:
Hello World Zhang lisi
5.3 从函数的返回值
例子:
#!/bin/bash
# Define your function here
Hello () {
echo "Hello World $1 $2"
return 1
}
# Invoke your function
Hello Zhangsan lisi
r=$?
echo "Return value is $r"

这将产生以下结果:
Hello World Zhangsan lisi
Return value is 1

5.4 嵌套函数
函数更有趣的功能之一是,他们可以调用本身以及调用其他函数。被称为递归函数调用自身的函数。
例子:
#!/bin/bash
# Calling one function from another
one () {
echo "This is the first function"
two
}

two () {
echo "This is the second function"
}
# Calling function one.
one

这将产生以下结果:
This is the first function
This is the second function
图片19.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则